Rollup merge of #118915 - compiler-errors:alias-nits, r=lcnr
Add some comments, add `can_define_opaque_ty` check to `try_normalize_ty_recur` Follow-up from #117278, since I was recently re-reviewing this code.
This commit is contained in:
commit
859874f3eb
8 changed files with 65 additions and 45 deletions
|
@ -315,7 +315,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||||
let mut failed = false;
|
let mut failed = false;
|
||||||
|
|
||||||
let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
|
let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
|
||||||
if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) {
|
if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
|
||||||
let default = tcx.object_lifetime_default(param.def_id);
|
let default = tcx.object_lifetime_default(param.def_id);
|
||||||
|
|
||||||
let re_static = tcx.lifetimes.re_static;
|
let re_static = tcx.lifetimes.re_static;
|
||||||
|
@ -339,7 +339,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||||
|
|
||||||
has_dyn = true;
|
has_dyn = true;
|
||||||
|
|
||||||
Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into()
|
Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
|
||||||
} else {
|
} else {
|
||||||
arg
|
arg
|
||||||
}
|
}
|
||||||
|
|
|
@ -2348,11 +2348,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
|
GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
|
||||||
GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
|
GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
|
||||||
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
||||||
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
|
ty::Projection | ty::Inherent => {
|
||||||
format!("the associated type `{p}`")
|
format!("the associated type `{p}`")
|
||||||
}
|
}
|
||||||
ty::AliasKind::Weak => format!("the type alias `{p}`"),
|
ty::Weak => format!("the type alias `{p}`"),
|
||||||
ty::AliasKind::Opaque => format!("the opaque type `{p}`"),
|
ty::Opaque => format!("the opaque type `{p}`"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -510,7 +510,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
match a_ty.kind() {
|
match a_ty.kind() {
|
||||||
&ty::Alias(ty::AliasKind::Projection, data) => {
|
&ty::Alias(ty::Projection, data) => {
|
||||||
// FIXME: This does not handle subtyping correctly, we could
|
// FIXME: This does not handle subtyping correctly, we could
|
||||||
// instead create a new inference variable for `a_ty`, emitting
|
// instead create a new inference variable for `a_ty`, emitting
|
||||||
// `Projection(a_ty, a_infer)` and `a_infer <: b_ty`.
|
// `Projection(a_ty, a_infer)` and `a_infer <: b_ty`.
|
||||||
|
@ -522,10 +522,9 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
// The old solver only accepts projection predicates for associated types.
|
// The old solver only accepts projection predicates for associated types.
|
||||||
ty::Alias(
|
ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => {
|
||||||
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque,
|
return Err(TypeError::CyclicTy(a_ty));
|
||||||
_,
|
}
|
||||||
) => return Err(TypeError::CyclicTy(a_ty)),
|
|
||||||
_ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
|
_ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ use rustc_span::{Span, Symbol};
|
||||||
use rustc_target::abi::{Abi, Size, WrappingRange};
|
use rustc_target::abi::{Abi, Size, WrappingRange};
|
||||||
use rustc_target::abi::{Integer, TagEncoding, Variants};
|
use rustc_target::abi::{Integer, TagEncoding, Variants};
|
||||||
use rustc_target::spec::abi::Abi as SpecAbi;
|
use rustc_target::spec::abi::Abi as SpecAbi;
|
||||||
use rustc_type_ir::DynKind;
|
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
@ -675,7 +674,7 @@ fn lint_wide_pointer<'tcx>(
|
||||||
}
|
}
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env))
|
ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env))
|
||||||
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, DynKind::Dyn)))),
|
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1225,7 +1225,7 @@ impl<'tcx> AliasTy<'tcx> {
|
||||||
|
|
||||||
/// Whether this alias type is an opaque.
|
/// Whether this alias type is an opaque.
|
||||||
pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
|
pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||||
matches!(self.opt_kind(tcx), Some(ty::AliasKind::Opaque))
|
matches!(self.opt_kind(tcx), Some(ty::Opaque))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME: rename `AliasTy` to `AliasTerm` and always handle
|
/// FIXME: rename `AliasTy` to `AliasTerm` and always handle
|
||||||
|
@ -2745,7 +2745,7 @@ impl<'tcx> Ty<'tcx> {
|
||||||
// Extern types have metadata = ().
|
// Extern types have metadata = ().
|
||||||
| ty::Foreign(..)
|
| ty::Foreign(..)
|
||||||
// `dyn*` has no metadata
|
// `dyn*` has no metadata
|
||||||
| ty::Dynamic(_, _, DynKind::DynStar)
|
| ty::Dynamic(_, _, ty::DynStar)
|
||||||
// If returned by `struct_tail_without_normalization` this is a unit struct
|
// If returned by `struct_tail_without_normalization` this is a unit struct
|
||||||
// without any fields, or not a struct, and therefore is Sized.
|
// without any fields, or not a struct, and therefore is Sized.
|
||||||
| ty::Adt(..)
|
| ty::Adt(..)
|
||||||
|
@ -2754,7 +2754,7 @@ impl<'tcx> Ty<'tcx> {
|
||||||
| ty::Tuple(..) => (tcx.types.unit, false),
|
| ty::Tuple(..) => (tcx.types.unit, false),
|
||||||
|
|
||||||
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
|
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
|
||||||
ty::Dynamic(_, _, DynKind::Dyn) => {
|
ty::Dynamic(_, _, ty::Dyn) => {
|
||||||
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
|
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
|
||||||
(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
|
(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,12 +12,11 @@ use crate::rustc_smir::{alloc, Stable, Tables};
|
||||||
impl<'tcx> Stable<'tcx> for ty::AliasKind {
|
impl<'tcx> Stable<'tcx> for ty::AliasKind {
|
||||||
type T = stable_mir::ty::AliasKind;
|
type T = stable_mir::ty::AliasKind;
|
||||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||||
use rustc_middle::ty::AliasKind::*;
|
|
||||||
match self {
|
match self {
|
||||||
Projection => stable_mir::ty::AliasKind::Projection,
|
ty::Projection => stable_mir::ty::AliasKind::Projection,
|
||||||
Inherent => stable_mir::ty::AliasKind::Inherent,
|
ty::Inherent => stable_mir::ty::AliasKind::Inherent,
|
||||||
Opaque => stable_mir::ty::AliasKind::Opaque,
|
ty::Opaque => stable_mir::ty::AliasKind::Opaque,
|
||||||
Weak => stable_mir::ty::AliasKind::Weak,
|
ty::Weak => stable_mir::ty::AliasKind::Weak,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,10 +33,9 @@ impl<'tcx> Stable<'tcx> for ty::DynKind {
|
||||||
type T = stable_mir::ty::DynKind;
|
type T = stable_mir::ty::DynKind;
|
||||||
|
|
||||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||||
use rustc_middle::ty::DynKind;
|
|
||||||
match self {
|
match self {
|
||||||
DynKind::Dyn => stable_mir::ty::DynKind::Dyn,
|
ty::Dyn => stable_mir::ty::DynKind::Dyn,
|
||||||
DynKind::DynStar => stable_mir::ty::DynKind::DynStar,
|
ty::DynStar => stable_mir::ty::DynKind::DynStar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,29 @@
|
||||||
//! Doing this via a separate goal is called "deferred alias relation" and part
|
//! Doing this via a separate goal is called "deferred alias relation" and part
|
||||||
//! of our more general approach to "lazy normalization".
|
//! of our more general approach to "lazy normalization".
|
||||||
//!
|
//!
|
||||||
//! This goal, e.g. `A alias-relate B`, may be satisfied by one of three branches:
|
//! This is done by first normalizing both sides of the goal, ending up in
|
||||||
//! * normalizes-to: If `A` is a projection, we can prove the equivalent
|
//! either a concrete type, rigid projection, opaque, or an infer variable.
|
||||||
//! projection predicate with B as the right-hand side of the projection.
|
//! These are related further according to the rules below:
|
||||||
//! This goal is computed in both directions, if both are aliases.
|
//!
|
||||||
//! * subst-relate: Equate `A` and `B` by their substs, if they're both
|
//! (1.) If we end up with a rigid projection and a rigid projection, then we
|
||||||
//! aliases with the same def-id.
|
//! relate those projections structurally.
|
||||||
//! * 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
|
//! (2.) If we end up with a rigid projection and an alias, then the opaque will
|
||||||
//! performing them together. This is used specifically to resolve ambiguities.
|
//! 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 super::{EvalCtxt, GoalSource};
|
||||||
use rustc_infer::infer::DefineOpaqueTypes;
|
use rustc_infer::infer::DefineOpaqueTypes;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
|
@ -50,6 +64,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
self.relate(param_env, lhs, variance, rhs)?;
|
self.relate(param_env, lhs, variance, rhs)?;
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
} else if alias.is_opaque(tcx) {
|
} else if alias.is_opaque(tcx) {
|
||||||
|
// FIXME: This doesn't account for variance.
|
||||||
self.define_opaque(param_env, alias, rhs)
|
self.define_opaque(param_env, alias, rhs)
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
|
@ -60,6 +75,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
self.relate(param_env, lhs, variance, rhs)?;
|
self.relate(param_env, lhs, variance, rhs)?;
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
} else if alias.is_opaque(tcx) {
|
} else if alias.is_opaque(tcx) {
|
||||||
|
// FIXME: This doesn't account for variance.
|
||||||
self.define_opaque(param_env, alias, lhs)
|
self.define_opaque(param_env, alias, lhs)
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
|
@ -72,6 +88,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.
|
/// Normalize the `term` to equate it later. This does not define opaque types.
|
||||||
#[instrument(level = "debug", skip(self, param_env), ret)]
|
#[instrument(level = "debug", skip(self, param_env), ret)]
|
||||||
fn try_normalize_term(
|
fn try_normalize_term(
|
||||||
|
|
|
@ -22,6 +22,7 @@ use rustc_middle::traits::solve::{
|
||||||
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
|
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
|
||||||
QueryResult, Response,
|
QueryResult, Response,
|
||||||
};
|
};
|
||||||
|
use rustc_middle::traits::Reveal;
|
||||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
|
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
||||||
|
@ -316,19 +317,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
return Some(ty);
|
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
|
||||||
if let (DefineOpaqueTypes::No, ty::AliasKind::Opaque) = (define_opaque_types, kind) {
|
// in the defining scope. However, if we can unify this opaque to an existing
|
||||||
if let Some(def_id) = alias.def_id.as_local() {
|
// opaque, then we should attempt to eagerly reveal the opaque, and we fall
|
||||||
if self
|
// through.
|
||||||
.unify_existing_opaque_tys(
|
if let DefineOpaqueTypes::No = define_opaque_types
|
||||||
param_env,
|
&& let Reveal::UserFacing = param_env.reveal()
|
||||||
OpaqueTypeKey { def_id, args: alias.args },
|
&& let ty::Opaque = kind
|
||||||
self.next_ty_infer(),
|
&& let Some(def_id) = alias.def_id.as_local()
|
||||||
)
|
&& self.can_define_opaque_ty(def_id)
|
||||||
.is_empty()
|
{
|
||||||
{
|
if self
|
||||||
return Some(ty);
|
.unify_existing_opaque_tys(
|
||||||
}
|
param_env,
|
||||||
|
OpaqueTypeKey { def_id, args: alias.args },
|
||||||
|
self.next_ty_infer(),
|
||||||
|
)
|
||||||
|
.is_empty()
|
||||||
|
{
|
||||||
|
return Some(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue