From c95961de5dd474c082242872170d24141e6f6282 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 10 Jan 2024 16:22:26 +0000 Subject: [PATCH] More comments --- .../src/solve/alias_relate.rs | 41 +++++++++++++++---- .../rustc_trait_selection/src/solve/mod.rs | 5 ++- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 626569fb40fc0..1377f4a00fb9e 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -2,15 +2,29 @@ //! Doing this via a separate goal is called "deferred alias relation" and part //! of our more general approach to "lazy normalization". //! -//! This goal, e.g. `A alias-relate B`, may be satisfied by one of three branches: -//! * normalizes-to: If `A` is a projection, we can prove the equivalent -//! projection predicate with B as the right-hand side of the projection. -//! This goal is computed in both directions, if both are aliases. -//! * subst-relate: Equate `A` and `B` by their substs, if they're both -//! aliases with the same def-id. -//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both -//! may apply, then we can compute the "intersection" of both normalizes-to by -//! performing them together. This is used specifically to resolve ambiguities. +//! This is done by first normalizing both sides of the goal, ending up in +//! either a concrete type, rigid projection, opaque, or an infer variable. +//! These are related further according to the rules below: +//! +//! (1.) If we end up with a rigid projection and a rigid projection, then we +//! relate those projections structurally. +//! +//! (2.) If we end up with a rigid projection and an alias, then the opaque will +//! have its hidden type defined to be that rigid projection. +//! +//! (3.) If we end up with an opaque and an opaque, then we assemble two +//! candidates, one defining the LHS to be the hidden type of the RHS, and vice +//! versa. +//! +//! (4.) If we end up with an infer var and an opaque or rigid projection, then +//! we assign the alias to the infer var. +//! +//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we +//! define the hidden type of the opaque to be the rigid type. +//! +//! (6.) Otherwise, if we end with two rigid (non-projection) or infer types, +//! relate them structurally. + use super::{EvalCtxt, GoalSource}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::query::NoSolution; @@ -45,11 +59,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } + // 1. When we have an alias being related to an infer var, then assign + // the type (or const) of the alias to the infer var. + // 2. When we have an opaque being related to a rigid type (which, due to 1, + // is not an infer var), then assign the hidden type of the opaque to be + // the rigid type. + // 3. Otherwise, a rigid projection does not equal a concrete type ever. (Some(alias), None) => { if rhs.is_infer() { self.relate(param_env, lhs, variance, rhs)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else if alias.is_opaque(tcx) { + // FIXME: This doesn't account for variance. self.define_opaque(param_env, alias, rhs) } else { Err(NoSolution) @@ -60,6 +81,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.relate(param_env, lhs, variance, rhs)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else if alias.is_opaque(tcx) { + // FIXME: This doesn't account for variance. self.define_opaque(param_env, alias, lhs) } else { Err(NoSolution) @@ -72,6 +94,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var. /// Normalize the `term` to equate it later. This does not define opaque types. #[instrument(level = "debug", skip(self, param_env), ret)] fn try_normalize_term( diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index dac8b3cce805f..7c8f885a1f24c 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -317,7 +317,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return Some(ty); }; - // We do no always define opaque types eagerly to allow non-defining uses in the defining scope. + // We do no always define opaque types eagerly to allow non-defining uses + // in the defining scope. However, if we can unify this opaque to an existing + // opaque, then we should attempt to eagerly reveal the opaque, and we fall + // through. if let DefineOpaqueTypes::No = define_opaque_types && let Reveal::UserFacing = param_env.reveal() && let ty::Opaque = kind