-
Notifications
You must be signed in to change notification settings - Fork 14k
Deeply normalize param env in compare_impl_item if using the next solver
#149345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -198,6 +198,8 @@ where | |
| if ty.has_escaping_bound_vars() { | ||
| let (ty, mapped_regions, mapped_types, mapped_consts) = | ||
| BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty); | ||
| // FIXME: Temporary placeholders may get added to infcx's region constraints/obligations, | ||
| // which can cause problem for `resolve_regions`. | ||
|
Comment on lines
+201
to
+202
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what do you mean here? I agree that we may get constraints involving placeholders from this, but that's fine™ We have the same behavior when relating binders and what not. The way we handle such placeholder constraints may change going forward and ideally we'd eagerly handle all of them when "exiting" the binder again, but for now "leaking" these constraints is normal |
||
| let result = | ||
| ensure_sufficient_stack(|| self.normalize_alias_term(ty.into()))?.expect_type(); | ||
| Ok(PlaceholderReplacer::replace_placeholders( | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -317,6 +317,58 @@ fn do_normalize_predicates<'tcx>( | |||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // A temporary hack. Do not use this. | ||||||||||||||||||||
| // See `deeply_normalize_param_env_or_error`. | ||||||||||||||||||||
| #[instrument(level = "debug", skip(tcx, elaborated_env))] | ||||||||||||||||||||
| fn do_deeply_normalize_predicates<'tcx>( | ||||||||||||||||||||
| tcx: TyCtxt<'tcx>, | ||||||||||||||||||||
| cause: ObligationCause<'tcx>, | ||||||||||||||||||||
| elaborated_env: ty::ParamEnv<'tcx>, | ||||||||||||||||||||
| predicates: Vec<ty::Clause<'tcx>>, | ||||||||||||||||||||
| ) -> Result<Vec<ty::Clause<'tcx>>, ErrorGuaranteed> { | ||||||||||||||||||||
| let span = cause.span; | ||||||||||||||||||||
| let infcx = tcx | ||||||||||||||||||||
| .infer_ctxt() | ||||||||||||||||||||
| .with_next_trait_solver(true) | ||||||||||||||||||||
| .ignoring_regions() | ||||||||||||||||||||
| .build(TypingMode::non_body_analysis()); | ||||||||||||||||||||
| let predicates = match crate::solve::deeply_normalize::<_, FulfillmentError<'tcx>>( | ||||||||||||||||||||
| infcx.at(&cause, elaborated_env), | ||||||||||||||||||||
| predicates, | ||||||||||||||||||||
| ) { | ||||||||||||||||||||
| Ok(predicates) => predicates, | ||||||||||||||||||||
| Err(errors) => { | ||||||||||||||||||||
| let reported = infcx.err_ctxt().report_fulfillment_errors(errors); | ||||||||||||||||||||
| return Err(reported); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| debug!("do_normalize_predicates: normalized predicates = {:?}", predicates); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // The next solver doesn't ignore region constraints so we do it manually. | ||||||||||||||||||||
| drop(infcx.take_registered_region_obligations()); | ||||||||||||||||||||
| drop(infcx.take_registered_region_assumptions()); | ||||||||||||||||||||
| drop(infcx.take_and_reset_region_constraints()); | ||||||||||||||||||||
|
Comment on lines
+349
to
+351
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, this feels... really bad xd like, that's kind of the point of what we're doing here, but still Does not dropping these things and instead not emitting a |
||||||||||||||||||||
| let errors = infcx.resolve_regions(cause.body_id, elaborated_env, []); | ||||||||||||||||||||
| if !errors.is_empty() { | ||||||||||||||||||||
| tcx.dcx().span_delayed_bug( | ||||||||||||||||||||
| span, | ||||||||||||||||||||
| format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"), | ||||||||||||||||||||
| ); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| match infcx.fully_resolve(predicates) { | ||||||||||||||||||||
| Ok(predicates) => Ok(predicates), | ||||||||||||||||||||
| Err(fixup_err) => { | ||||||||||||||||||||
| span_bug!( | ||||||||||||||||||||
| span, | ||||||||||||||||||||
| "inference variables in normalized parameter environment: {}", | ||||||||||||||||||||
| fixup_err | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // FIXME: this is gonna need to be removed ... | ||||||||||||||||||||
| /// Normalizes the parameter environment, reporting errors if they occur. | ||||||||||||||||||||
| #[instrument(level = "debug", skip(tcx))] | ||||||||||||||||||||
|
|
@@ -477,6 +529,66 @@ pub fn normalize_param_env_or_error<'tcx>( | |||||||||||||||||||
| ty::ParamEnv::new(tcx.mk_clauses(&predicates)) | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // FIXME(-Zhigher-ranked-assumptions): this is a hack to walk around the fact that we don't support | ||||||||||||||||||||
| // placeholder assumptions right now. | ||||||||||||||||||||
| // We should remove this once we have proper support for implied bounds on binders. | ||||||||||||||||||||
| /// Deeply normalize the param env using the next solver. | ||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
elaborated a bit and also want the FIXME to be part of the doc comment. The fact that this function is somewhat scuffed and shouldn't be used should be visible in the docs |
||||||||||||||||||||
| #[instrument(level = "debug", skip(tcx))] | ||||||||||||||||||||
| pub fn deeply_normalize_param_env_or_error<'tcx>( | ||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||
| tcx: TyCtxt<'tcx>, | ||||||||||||||||||||
| unnormalized_env: ty::ParamEnv<'tcx>, | ||||||||||||||||||||
| cause: ObligationCause<'tcx>, | ||||||||||||||||||||
| ) -> ty::ParamEnv<'tcx> { | ||||||||||||||||||||
| let mut predicates: Vec<_> = | ||||||||||||||||||||
| util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates)); | ||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't think we have to create a new wanna update the new solver to just use the |
||||||||||||||||||||
| if !elaborated_env.has_aliases() { | ||||||||||||||||||||
| return elaborated_env; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| let outlives_predicates: Vec<_> = predicates | ||||||||||||||||||||
| .extract_if(.., |predicate| { | ||||||||||||||||||||
| matches!(predicate.kind().skip_binder(), ty::ClauseKind::TypeOutlives(..)) | ||||||||||||||||||||
| }) | ||||||||||||||||||||
| .collect(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| debug!( | ||||||||||||||||||||
| "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})", | ||||||||||||||||||||
| predicates, outlives_predicates | ||||||||||||||||||||
| ); | ||||||||||||||||||||
| let Ok(non_outlives_predicates) = | ||||||||||||||||||||
| do_deeply_normalize_predicates(tcx, cause.clone(), elaborated_env, predicates) | ||||||||||||||||||||
| else { | ||||||||||||||||||||
| // An unnormalized env is better than nothing. | ||||||||||||||||||||
| debug!("normalize_param_env_or_error: errored resolving non-outlives predicates"); | ||||||||||||||||||||
| return elaborated_env; | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Not sure whether it is better to include the unnormalized TypeOutlives predicates | ||||||||||||||||||||
| // here. I believe they should not matter, because we are ignoring TypeOutlives param-env | ||||||||||||||||||||
| // predicates here anyway. Keeping them here anyway because it seems safer. | ||||||||||||||||||||
| let outlives_env = non_outlives_predicates.iter().chain(&outlives_predicates).cloned(); | ||||||||||||||||||||
| let outlives_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(outlives_env)); | ||||||||||||||||||||
| let Ok(outlives_predicates) = | ||||||||||||||||||||
| do_deeply_normalize_predicates(tcx, cause, outlives_env, outlives_predicates) | ||||||||||||||||||||
| else { | ||||||||||||||||||||
| // An unnormalized env is better than nothing. | ||||||||||||||||||||
| debug!("normalize_param_env_or_error: errored resolving outlives predicates"); | ||||||||||||||||||||
| return elaborated_env; | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't need to split outlives vs non-outlives predicate norm in the new solver. This only matters for the old one
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that way you also don't need a separate |
||||||||||||||||||||
| debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| let mut predicates = non_outlives_predicates; | ||||||||||||||||||||
| predicates.extend(outlives_predicates); | ||||||||||||||||||||
| debug!("normalize_param_env_or_error: final predicates={:?}", predicates); | ||||||||||||||||||||
| ty::ParamEnv::new(tcx.mk_clauses(&predicates)) | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| #[derive(Debug)] | ||||||||||||||||||||
| pub enum EvaluateConstErr { | ||||||||||||||||||||
| /// The constant being evaluated was either a generic parameter or inference variable, *or*, | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| //@ check-pass | ||
| //@ compile-flags: -Znext-solver | ||
|
|
||
| // See trait-system-refactor-initiative/issues/166. | ||
| // The old solver doesn't check normalization constraints in `compare_impl_item`. | ||
| // The new solver performs lazy normalization so those region constraints may get postponed to | ||
| // an infcx that considers regions. | ||
| trait Trait { | ||
| type Assoc<'a> | ||
| where | ||
| Self: 'a; | ||
| } | ||
| impl<'b> Trait for &'b u32 { | ||
| type Assoc<'a> = &'a u32 | ||
| where | ||
| Self: 'a; | ||
| } | ||
|
|
||
| trait Bound<T> {} | ||
| trait Entailment<T: Trait> { | ||
| fn method() | ||
| where | ||
| Self: for<'a> Bound<<T as Trait>::Assoc<'a>>; | ||
| } | ||
|
|
||
| impl<'b, T> Entailment<&'b u32> for T { | ||
| // Instantiates trait where-clauses with `&'b u32` and then normalizes | ||
| // `T: for<'a> Bound<<&'b u32 as Trait>::Assoc<'a>>` in a separate infcx | ||
| // without checking region constraints. | ||
| // | ||
| // It normalizes to `T: Bound<&'a u32>`, dropping the `&'b u32: 'a` constraint. | ||
| fn method() | ||
| where | ||
| Self: for<'a> Bound<&'a u32> | ||
| {} | ||
| } | ||
|
|
||
| fn main() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
elaborated a bit here