support revealing defined opaque post borrowck
This commit is contained in:
parent
18e2253e79
commit
34a8c2dbba
21 changed files with 226 additions and 58 deletions
|
@ -322,8 +322,12 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||||
};
|
};
|
||||||
let param_env = tcx.param_env(defining_use_anchor);
|
let param_env = tcx.param_env(defining_use_anchor);
|
||||||
|
|
||||||
// FIXME(#132279): This should eventually use the already defined hidden types.
|
// FIXME(#132279): Once `PostBorrowckAnalysis` is supported in the old solver, this branch should be removed.
|
||||||
let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor));
|
let infcx = tcx.infer_ctxt().build(if tcx.next_trait_solver_globally() {
|
||||||
|
TypingMode::post_borrowck_analysis(tcx, defining_use_anchor)
|
||||||
|
} else {
|
||||||
|
TypingMode::analysis_in_body(tcx, defining_use_anchor)
|
||||||
|
});
|
||||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
||||||
|
|
||||||
let args = match origin {
|
let args = match origin {
|
||||||
|
@ -417,7 +421,11 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||||
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
|
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
|
||||||
|
|
||||||
if let hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } = origin {
|
if infcx.next_trait_solver() {
|
||||||
|
Ok(())
|
||||||
|
} else if let hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } =
|
||||||
|
origin
|
||||||
|
{
|
||||||
// HACK: this should also fall through to the hidden type check below, but the original
|
// HACK: this should also fall through to the hidden type check below, but the original
|
||||||
// implementation had a bug where equivalent lifetimes are not identical. This caused us
|
// implementation had a bug where equivalent lifetimes are not identical. This caused us
|
||||||
// to reject existing stable code that is otherwise completely fine. The real fix is to
|
// to reject existing stable code that is otherwise completely fine. The real fix is to
|
||||||
|
|
|
@ -1574,7 +1574,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
// Thus we need to prevent them from trying to match the `&_` autoref
|
// Thus we need to prevent them from trying to match the `&_` autoref
|
||||||
// candidates that get created for `&self` trait methods.
|
// candidates that get created for `&self` trait methods.
|
||||||
ty::Alias(ty::Opaque, alias_ty)
|
ty::Alias(ty::Opaque, alias_ty)
|
||||||
if self.infcx.can_define_opaque_ty(alias_ty.def_id)
|
if !self.next_trait_solver()
|
||||||
|
&& self.infcx.can_define_opaque_ty(alias_ty.def_id)
|
||||||
&& !xform_self_ty.is_ty_var() =>
|
&& !xform_self_ty.is_ty_var() =>
|
||||||
{
|
{
|
||||||
return ProbeResult::NoMatch;
|
return ProbeResult::NoMatch;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed};
|
use rustc_span::{DUMMY_SP, ErrorGuaranteed};
|
||||||
|
|
||||||
use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin};
|
use super::{BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin};
|
||||||
|
|
||||||
impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
||||||
type Interner = TyCtxt<'tcx>;
|
type Interner = TyCtxt<'tcx>;
|
||||||
|
@ -87,6 +87,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
||||||
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
|
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_region_infer(&self) -> ty::Region<'tcx> {
|
||||||
|
self.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
|
||||||
|
}
|
||||||
|
|
||||||
fn next_ty_infer(&self) -> Ty<'tcx> {
|
fn next_ty_infer(&self) -> Ty<'tcx> {
|
||||||
self.next_ty_var(DUMMY_SP)
|
self.next_ty_var(DUMMY_SP)
|
||||||
}
|
}
|
||||||
|
|
|
@ -990,11 +990,17 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
|
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
|
||||||
|
debug_assert!(!self.next_trait_solver());
|
||||||
match self.typing_mode() {
|
match self.typing_mode() {
|
||||||
TypingMode::Analysis { defining_opaque_types } => {
|
TypingMode::Analysis { defining_opaque_types } => {
|
||||||
id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
|
id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
|
||||||
}
|
}
|
||||||
TypingMode::Coherence | TypingMode::PostAnalysis => false,
|
// FIXME(#132279): This function is quite weird in post-analysis
|
||||||
|
// and post-borrowck analysis mode. We may need to modify its uses
|
||||||
|
// to support PostBorrowckAnalysis in the old solver as well.
|
||||||
|
TypingMode::Coherence
|
||||||
|
| TypingMode::PostBorrowckAnalysis { .. }
|
||||||
|
| TypingMode::PostAnalysis => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1276,7 +1282,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
/// using canonicalization or carrying this inference context around.
|
/// using canonicalization or carrying this inference context around.
|
||||||
pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> {
|
pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> {
|
||||||
let typing_mode = match self.typing_mode() {
|
let typing_mode = match self.typing_mode() {
|
||||||
ty::TypingMode::Coherence => ty::TypingMode::Coherence,
|
|
||||||
// FIXME(#132279): This erases the `defining_opaque_types` as it isn't possible
|
// FIXME(#132279): This erases the `defining_opaque_types` as it isn't possible
|
||||||
// to handle them without proper canonicalization. This means we may cause cycle
|
// to handle them without proper canonicalization. This means we may cause cycle
|
||||||
// errors and fail to reveal opaques while inside of bodies. We should rename this
|
// errors and fail to reveal opaques while inside of bodies. We should rename this
|
||||||
|
@ -1284,7 +1289,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
ty::TypingMode::Analysis { defining_opaque_types: _ } => {
|
ty::TypingMode::Analysis { defining_opaque_types: _ } => {
|
||||||
TypingMode::non_body_analysis()
|
TypingMode::non_body_analysis()
|
||||||
}
|
}
|
||||||
ty::TypingMode::PostAnalysis => ty::TypingMode::PostAnalysis,
|
mode @ (ty::TypingMode::Coherence
|
||||||
|
| ty::TypingMode::PostBorrowckAnalysis { .. }
|
||||||
|
| ty::TypingMode::PostAnalysis) => mode,
|
||||||
};
|
};
|
||||||
ty::TypingEnv { typing_mode, param_env }
|
ty::TypingEnv { typing_mode, param_env }
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, TypeError<'tcx>> {
|
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, TypeError<'tcx>> {
|
||||||
|
debug_assert!(!self.next_trait_solver());
|
||||||
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
|
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
|
||||||
let def_id = def_id.expect_local();
|
let def_id = def_id.expect_local();
|
||||||
|
@ -546,7 +547,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::TypingMode::PostAnalysis => bug!("insert hidden type post-analysis"),
|
mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => {
|
||||||
|
bug!("insert hidden type in {mode:?}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -339,7 +339,9 @@ where
|
||||||
|
|
||||||
match self.typing_mode() {
|
match self.typing_mode() {
|
||||||
TypingMode::Coherence => {}
|
TypingMode::Coherence => {}
|
||||||
TypingMode::Analysis { .. } | TypingMode::PostAnalysis => {
|
TypingMode::Analysis { .. }
|
||||||
|
| TypingMode::PostBorrowckAnalysis { .. }
|
||||||
|
| TypingMode::PostAnalysis => {
|
||||||
self.discard_impls_shadowed_by_env(goal, &mut candidates);
|
self.discard_impls_shadowed_by_env(goal, &mut candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -644,6 +644,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn next_region_var(&mut self) -> I::Region {
|
||||||
|
let region = self.delegate.next_region_infer();
|
||||||
|
self.inspect.add_var_value(region);
|
||||||
|
region
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn next_ty_infer(&mut self) -> I::Ty {
|
pub(super) fn next_ty_infer(&mut self) -> I::Ty {
|
||||||
let ty = self.delegate.next_ty_infer();
|
let ty = self.delegate.next_ty_infer();
|
||||||
self.inspect.add_var_value(ty);
|
self.inspect.add_var_value(ty);
|
||||||
|
|
|
@ -23,7 +23,7 @@ mod trait_goals;
|
||||||
|
|
||||||
use rustc_type_ir::inherent::*;
|
use rustc_type_ir::inherent::*;
|
||||||
pub use rustc_type_ir::solve::*;
|
pub use rustc_type_ir::solve::*;
|
||||||
use rustc_type_ir::{self as ty, Interner};
|
use rustc_type_ir::{self as ty, Interner, TypingMode};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt};
|
pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt};
|
||||||
|
@ -321,6 +321,19 @@ where
|
||||||
Ok(ct)
|
Ok(ct)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn opaque_type_is_rigid(&self, def_id: I::DefId) -> bool {
|
||||||
|
match self.typing_mode() {
|
||||||
|
// Opaques are never rigid outside of analysis mode.
|
||||||
|
TypingMode::Coherence | TypingMode::PostAnalysis => false,
|
||||||
|
// During analysis, opaques are rigid unless they may be defined by
|
||||||
|
// the current body.
|
||||||
|
TypingMode::Analysis { defining_opaque_types: non_rigid_opaques }
|
||||||
|
| TypingMode::PostBorrowckAnalysis { defined_opaque_types: non_rigid_opaques } => {
|
||||||
|
!def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn response_no_constraints_raw<I: Interner>(
|
fn response_no_constraints_raw<I: Interner>(
|
||||||
|
|
|
@ -6,7 +6,7 @@ mod weak_types;
|
||||||
use rustc_type_ir::fast_reject::DeepRejectCtxt;
|
use rustc_type_ir::fast_reject::DeepRejectCtxt;
|
||||||
use rustc_type_ir::inherent::*;
|
use rustc_type_ir::inherent::*;
|
||||||
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||||
use rustc_type_ir::{self as ty, Interner, NormalizesTo, TypingMode, Upcast as _};
|
use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use crate::delegate::SolverDelegate;
|
use crate::delegate::SolverDelegate;
|
||||||
|
@ -71,21 +71,10 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
ty::AliasTermKind::OpaqueTy => {
|
ty::AliasTermKind::OpaqueTy => {
|
||||||
match self.typing_mode() {
|
if self.opaque_type_is_rigid(rigid_alias.def_id) {
|
||||||
// Opaques are never rigid outside of analysis mode.
|
|
||||||
TypingMode::Coherence | TypingMode::PostAnalysis => Err(NoSolution),
|
|
||||||
// During analysis, opaques are only rigid if we may not define it.
|
|
||||||
TypingMode::Analysis { defining_opaque_types } => {
|
|
||||||
if rigid_alias
|
|
||||||
.def_id
|
|
||||||
.as_local()
|
|
||||||
.is_some_and(|def_id| defining_opaque_types.contains(&def_id))
|
|
||||||
{
|
|
||||||
Err(NoSolution)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
} else {
|
||||||
}
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME(generic_const_exprs): we would need to support generic consts here
|
// FIXME(generic_const_exprs): we would need to support generic consts here
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
//! behaves differently depending on the current `TypingMode`.
|
//! behaves differently depending on the current `TypingMode`.
|
||||||
|
|
||||||
use rustc_index::bit_set::GrowableBitSet;
|
use rustc_index::bit_set::GrowableBitSet;
|
||||||
|
use rustc_type_ir::fold::fold_regions;
|
||||||
use rustc_type_ir::inherent::*;
|
use rustc_type_ir::inherent::*;
|
||||||
use rustc_type_ir::{self as ty, Interner, TypingMode};
|
use rustc_type_ir::{self as ty, Interner, TypingMode};
|
||||||
|
|
||||||
|
@ -95,6 +96,26 @@ where
|
||||||
);
|
);
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
}
|
}
|
||||||
|
TypingMode::PostBorrowckAnalysis { defined_opaque_types } => {
|
||||||
|
let Some(def_id) = opaque_ty.def_id.as_local() else {
|
||||||
|
return Err(NoSolution);
|
||||||
|
};
|
||||||
|
|
||||||
|
if !defined_opaque_types.contains(&def_id) {
|
||||||
|
return Err(NoSolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args);
|
||||||
|
// FIXME: Actually use a proper binder here instead of relying on `ReErased`.
|
||||||
|
//
|
||||||
|
// This is also probably unsound or sth :shrug:
|
||||||
|
let actual = fold_regions(cx, actual, |re, _dbi| match re.kind() {
|
||||||
|
ty::ReErased => self.next_region_var(),
|
||||||
|
_ => re,
|
||||||
|
});
|
||||||
|
self.eq(goal.param_env, expected, actual)?;
|
||||||
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
}
|
||||||
TypingMode::PostAnalysis => {
|
TypingMode::PostAnalysis => {
|
||||||
// FIXME: Add an assertion that opaque type storage is empty.
|
// FIXME: Add an assertion that opaque type storage is empty.
|
||||||
let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args);
|
let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args);
|
||||||
|
|
|
@ -69,7 +69,9 @@ where
|
||||||
// it's not a real impl.
|
// it's not a real impl.
|
||||||
(ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
|
(ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
|
||||||
TypingMode::Coherence => Certainty::AMBIGUOUS,
|
TypingMode::Coherence => Certainty::AMBIGUOUS,
|
||||||
TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Err(NoSolution),
|
TypingMode::Analysis { .. }
|
||||||
|
| TypingMode::PostBorrowckAnalysis { .. }
|
||||||
|
| TypingMode::PostAnalysis => return Err(NoSolution),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Impl matches polarity
|
// Impl matches polarity
|
||||||
|
@ -174,20 +176,7 @@ where
|
||||||
// ideally we want to avoid, since we can make progress on this goal
|
// ideally we want to avoid, since we can make progress on this goal
|
||||||
// via an alias bound or a locally-inferred hidden type instead.
|
// via an alias bound or a locally-inferred hidden type instead.
|
||||||
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
|
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
|
||||||
match ecx.typing_mode() {
|
debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
|
||||||
TypingMode::Coherence | TypingMode::PostAnalysis => {
|
|
||||||
unreachable!("rigid opaque outside of analysis: {goal:?}");
|
|
||||||
}
|
|
||||||
TypingMode::Analysis { defining_opaque_types } => {
|
|
||||||
if opaque_ty
|
|
||||||
.def_id
|
|
||||||
.as_local()
|
|
||||||
.is_some_and(|def_id| defining_opaque_types.contains(&def_id))
|
|
||||||
{
|
|
||||||
return Err(NoSolution);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||||
|
|
|
@ -205,7 +205,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
||||||
// transmute checking and polymorphic MIR optimizations could
|
// transmute checking and polymorphic MIR optimizations could
|
||||||
// get a result which isn't correct for all monomorphizations.
|
// get a result which isn't correct for all monomorphizations.
|
||||||
match self.typing_mode() {
|
match self.typing_mode() {
|
||||||
TypingMode::Coherence | TypingMode::Analysis { .. } => false,
|
TypingMode::Coherence
|
||||||
|
| TypingMode::Analysis { .. }
|
||||||
|
| TypingMode::PostBorrowckAnalysis { .. } => false,
|
||||||
TypingMode::PostAnalysis => {
|
TypingMode::PostAnalysis => {
|
||||||
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
|
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
|
||||||
!poly_trait_ref.still_further_specializable()
|
!poly_trait_ref.still_further_specializable()
|
||||||
|
|
|
@ -118,9 +118,10 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||||
// Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
|
// Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
|
||||||
// so we can ignore those.
|
// so we can ignore those.
|
||||||
match infcx.typing_mode() {
|
match infcx.typing_mode() {
|
||||||
TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
|
// FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
|
||||||
flags.remove(ty::TypeFlags::HAS_TY_OPAQUE)
|
TypingMode::Coherence
|
||||||
}
|
| TypingMode::Analysis { .. }
|
||||||
|
| TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
|
||||||
TypingMode::PostAnalysis => {}
|
TypingMode::PostAnalysis => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,9 +214,10 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
||||||
ty::Opaque => {
|
ty::Opaque => {
|
||||||
// Only normalize `impl Trait` outside of type inference, usually in codegen.
|
// Only normalize `impl Trait` outside of type inference, usually in codegen.
|
||||||
match self.selcx.infcx.typing_mode() {
|
match self.selcx.infcx.typing_mode() {
|
||||||
TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
|
// FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
|
||||||
ty.super_fold_with(self)
|
TypingMode::Coherence
|
||||||
}
|
| TypingMode::Analysis { .. }
|
||||||
|
| TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self),
|
||||||
TypingMode::PostAnalysis => {
|
TypingMode::PostAnalysis => {
|
||||||
let recursion_limit = self.cx().recursion_limit();
|
let recursion_limit = self.cx().recursion_limit();
|
||||||
if !recursion_limit.value_within_limit(self.depth) {
|
if !recursion_limit.value_within_limit(self.depth) {
|
||||||
|
|
|
@ -975,7 +975,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||||
// transmute checking and polymorphic MIR optimizations could
|
// transmute checking and polymorphic MIR optimizations could
|
||||||
// get a result which isn't correct for all monomorphizations.
|
// get a result which isn't correct for all monomorphizations.
|
||||||
match selcx.infcx.typing_mode() {
|
match selcx.infcx.typing_mode() {
|
||||||
TypingMode::Coherence | TypingMode::Analysis { .. } => {
|
TypingMode::Coherence
|
||||||
|
| TypingMode::Analysis { .. }
|
||||||
|
| TypingMode::PostBorrowckAnalysis { .. } => {
|
||||||
debug!(
|
debug!(
|
||||||
assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
|
assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
|
||||||
?obligation.predicate,
|
?obligation.predicate,
|
||||||
|
|
|
@ -216,9 +216,9 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
|
||||||
ty::Opaque => {
|
ty::Opaque => {
|
||||||
// Only normalize `impl Trait` outside of type inference, usually in codegen.
|
// Only normalize `impl Trait` outside of type inference, usually in codegen.
|
||||||
match self.infcx.typing_mode() {
|
match self.infcx.typing_mode() {
|
||||||
TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
|
TypingMode::Coherence
|
||||||
ty.try_super_fold_with(self)?
|
| TypingMode::Analysis { .. }
|
||||||
}
|
| TypingMode::PostBorrowckAnalysis { .. } => ty.try_super_fold_with(self)?,
|
||||||
|
|
||||||
TypingMode::PostAnalysis => {
|
TypingMode::PostAnalysis => {
|
||||||
let args = data.args.try_fold_with(self)?;
|
let args = data.args.try_fold_with(self)?;
|
||||||
|
|
|
@ -1471,7 +1471,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let obligation = &stack.obligation;
|
let obligation = &stack.obligation;
|
||||||
match self.infcx.typing_mode() {
|
match self.infcx.typing_mode() {
|
||||||
TypingMode::Coherence => {}
|
TypingMode::Coherence => {}
|
||||||
TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Ok(()),
|
TypingMode::Analysis { .. }
|
||||||
|
| TypingMode::PostBorrowckAnalysis { .. }
|
||||||
|
| TypingMode::PostAnalysis => return Ok(()),
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("is_knowable()");
|
debug!("is_knowable()");
|
||||||
|
@ -1518,6 +1520,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
TypingMode::Analysis { defining_opaque_types } => {
|
TypingMode::Analysis { defining_opaque_types } => {
|
||||||
defining_opaque_types.is_empty() || !pred.has_opaque_types()
|
defining_opaque_types.is_empty() || !pred.has_opaque_types()
|
||||||
}
|
}
|
||||||
|
// The hidden types of `defined_opaque_types` is not local to the current
|
||||||
|
// inference context, so we can freely move this to the global cache.
|
||||||
|
TypingMode::PostBorrowckAnalysis { .. } => true,
|
||||||
// The global cache is only used if there are no opaque types in
|
// The global cache is only used if there are no opaque types in
|
||||||
// the defining scope or we're outside of analysis.
|
// the defining scope or we're outside of analysis.
|
||||||
//
|
//
|
||||||
|
|
|
@ -149,7 +149,8 @@ fn resolve_associated_item<'tcx>(
|
||||||
// get a result which isn't correct for all monomorphizations.
|
// get a result which isn't correct for all monomorphizations.
|
||||||
match typing_env.typing_mode {
|
match typing_env.typing_mode {
|
||||||
ty::TypingMode::Coherence
|
ty::TypingMode::Coherence
|
||||||
| ty::TypingMode::Analysis { defining_opaque_types: _ } => false,
|
| ty::TypingMode::Analysis { .. }
|
||||||
|
| ty::TypingMode::PostBorrowckAnalysis { .. } => false,
|
||||||
ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(),
|
ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,6 +63,12 @@ pub enum TypingMode<I: Interner> {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
Analysis { defining_opaque_types: I::DefiningOpaqueTypes },
|
Analysis { defining_opaque_types: I::DefiningOpaqueTypes },
|
||||||
|
/// Any analysis after borrowck for a given body should be able to use all the
|
||||||
|
/// hidden types defined by borrowck, without being able to define any new ones.
|
||||||
|
///
|
||||||
|
/// This is currently only used by the new solver, but should be implemented in
|
||||||
|
/// the old solver as well.
|
||||||
|
PostBorrowckAnalysis { defined_opaque_types: I::DefiningOpaqueTypes },
|
||||||
/// After analysis, mostly during codegen and MIR optimizations, we're able to
|
/// After analysis, mostly during codegen and MIR optimizations, we're able to
|
||||||
/// reveal all opaque types. As the concrete type should *never* be observable
|
/// reveal all opaque types. As the concrete type should *never* be observable
|
||||||
/// directly by the user, this should not be used by checks which may expose
|
/// directly by the user, this should not be used by checks which may expose
|
||||||
|
@ -85,6 +91,12 @@ impl<I: Interner> TypingMode<I> {
|
||||||
pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
|
pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
|
||||||
TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
|
TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn post_borrowck_analysis(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
|
||||||
|
TypingMode::PostBorrowckAnalysis {
|
||||||
|
defined_opaque_types: cx.opaque_types_defined_by(body_def_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait InferCtxtLike: Sized {
|
pub trait InferCtxtLike: Sized {
|
||||||
|
@ -126,6 +138,7 @@ pub trait InferCtxtLike: Sized {
|
||||||
vid: ty::RegionVid,
|
vid: ty::RegionVid,
|
||||||
) -> <Self::Interner as Interner>::Region;
|
) -> <Self::Interner as Interner>::Region;
|
||||||
|
|
||||||
|
fn next_region_infer(&self) -> <Self::Interner as Interner>::Region;
|
||||||
fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
|
fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
|
||||||
fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
|
fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
|
||||||
fn fresh_args_for_item(
|
fn fresh_args_for_item(
|
||||||
|
|
|
@ -136,9 +136,9 @@ where
|
||||||
relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
|
relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
|
||||||
Ok(a)
|
Ok(a)
|
||||||
}
|
}
|
||||||
TypingMode::Analysis { .. } | TypingMode::PostAnalysis => {
|
TypingMode::Analysis { .. }
|
||||||
structurally_relate_tys(relation, a, b)
|
| TypingMode::PostBorrowckAnalysis { .. }
|
||||||
}
|
| TypingMode::PostAnalysis => structurally_relate_tys(relation, a, b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
error: unconstrained opaque type
|
||||||
|
--> $DIR/no-define-in-wf-check.rs:19:18
|
||||||
|
|
|
||||||
|
LL | type Tait1 = impl Sized;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `Tait1` must be used in combination with a concrete type within the same module
|
||||||
|
|
||||||
|
error: unconstrained opaque type
|
||||||
|
--> $DIR/no-define-in-wf-check.rs:27:18
|
||||||
|
|
|
||||||
|
LL | type Tait1 = impl Sized;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `Tait1` must be used in combination with a concrete type within the same module
|
||||||
|
|
||||||
|
error: unconstrained opaque type
|
||||||
|
--> $DIR/no-define-in-wf-check.rs:36:18
|
||||||
|
|
|
||||||
|
LL | type Tait1 = impl Sized;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `Tait1` must be used in combination with a concrete type within the same module
|
||||||
|
|
||||||
|
error: unconstrained opaque type
|
||||||
|
--> $DIR/no-define-in-wf-check.rs:47:18
|
||||||
|
|
|
||||||
|
LL | type Tait1 = impl Sized;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `Tait1` must be used in combination with a concrete type within the same module
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
66
tests/ui/traits/next-solver/opaques/no-define-in-wf-check.rs
Normal file
66
tests/ui/traits/next-solver/opaques/no-define-in-wf-check.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
//@[next] check-pass
|
||||||
|
|
||||||
|
// Regression test for trait-system-refactor-initiative#106. We previously
|
||||||
|
// tried to define other opaques while checking that opaques are well-formed.
|
||||||
|
//
|
||||||
|
// This resulted in undesirable ambiguity
|
||||||
|
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
mod ex0 {
|
||||||
|
fn foo() -> (impl Sized, impl Sized) {
|
||||||
|
((), ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mod ex1 {
|
||||||
|
type Tait1 = impl Sized;
|
||||||
|
//[current]~^ ERROR unconstrained opaque type
|
||||||
|
fn foo(x: Tait1) -> impl Sized {
|
||||||
|
let () = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod ex2 {
|
||||||
|
type Tait1 = impl Sized;
|
||||||
|
//[current]~^ ERROR unconstrained opaque type
|
||||||
|
type Tait2 = impl Sized;
|
||||||
|
fn foo(x: Tait1) -> Tait2 {
|
||||||
|
let () = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod ex3 {
|
||||||
|
type Tait1 = impl Sized;
|
||||||
|
//[current]~^ ERROR unconstrained opaque type
|
||||||
|
trait Something<T> {}
|
||||||
|
impl<T, U> Something<U> for T {}
|
||||||
|
type Tait2 = impl Something<Tait1>;
|
||||||
|
fn foo(x: Tait1) -> Tait2 {
|
||||||
|
let () = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod ex4 {
|
||||||
|
type Tait1 = impl Sized;
|
||||||
|
//[current]~^ ERROR unconstrained opaque type
|
||||||
|
trait Trait<U> {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> Trait<U> for T {
|
||||||
|
type Assoc = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ambiguity when checking that `Tait2` is wf
|
||||||
|
//
|
||||||
|
// ambiguity proving `(): Trait<Tait1>`.
|
||||||
|
type Tait2 = impl Trait<(), Assoc = impl Trait<Tait1>>;
|
||||||
|
fn foo(x: Tait1) -> Tait2 {
|
||||||
|
let () = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue