summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/ty/relate.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_middle/src/ty/relate.rs
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_middle/src/ty/relate.rs')
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs101
1 files changed, 83 insertions, 18 deletions
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index b25b4bd4f..c759fb6d5 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -5,7 +5,7 @@
//! subtyping, type equality, etc.
use crate::ty::error::{ExpectedFound, TypeError};
-use crate::ty::{self, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, Expr, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable};
use crate::ty::{GenericArg, GenericArgKind, SubstsRef};
use rustc_hir as ast;
use rustc_hir::def_id::DefId;
@@ -23,6 +23,8 @@ pub enum Cause {
pub trait TypeRelation<'tcx>: Sized {
fn tcx(&self) -> TyCtxt<'tcx>;
+ fn intercrate(&self) -> bool;
+
fn param_env(&self) -> ty::ParamEnv<'tcx>;
/// Returns a static string we can use for printouts.
@@ -32,6 +34,9 @@ pub trait TypeRelation<'tcx>: Sized {
/// relation. Just affects error messages.
fn a_is_expected(&self) -> bool;
+ /// Used during coherence. If called, must emit an always-ambiguous obligation.
+ fn mark_ambiguous(&mut self);
+
fn with_cause<F, R>(&mut self, _cause: Cause, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
@@ -60,7 +65,7 @@ pub trait TypeRelation<'tcx>: Sized {
let tcx = self.tcx();
let opt_variances = tcx.variances_of(item_def_id);
- relate_substs_with_variances(self, item_def_id, opt_variances, a_subst, b_subst)
+ relate_substs_with_variances(self, item_def_id, opt_variances, a_subst, b_subst, true)
}
/// Switch variance for the purpose of relating `a` and `b`.
@@ -151,13 +156,14 @@ pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>(
variances: &[ty::Variance],
a_subst: SubstsRef<'tcx>,
b_subst: SubstsRef<'tcx>,
+ fetch_ty_for_diag: bool,
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
let tcx = relation.tcx();
let mut cached_ty = None;
let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
let variance = variances[i];
- let variance_info = if variance == ty::Invariant {
+ let variance_info = if variance == ty::Invariant && fetch_ty_for_diag {
let ty =
*cached_ty.get_or_insert_with(|| tcx.bound_type_of(ty_def_id).subst(tcx, a_subst));
ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
@@ -561,8 +567,23 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
(&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
if a_def_id == b_def_id =>
{
- let substs = relate_substs(relation, a_substs, b_substs)?;
- Ok(tcx.mk_opaque(a_def_id, substs))
+ if relation.intercrate() {
+ // During coherence, opaque types should be treated as equal to each other, even if their generic params
+ // differ, as they could resolve to the same hidden type, even for different generic params.
+ relation.mark_ambiguous();
+ Ok(a)
+ } else {
+ let opt_variances = tcx.variances_of(a_def_id);
+ let substs = relate_substs_with_variances(
+ relation,
+ a_def_id,
+ opt_variances,
+ a_substs,
+ b_substs,
+ false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
+ )?;
+ Ok(tcx.mk_opaque(a_def_id, substs))
+ }
}
_ => Err(TypeError::Sorts(expected_found(relation, a, b))),
@@ -592,7 +613,10 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
if a_ty != b_ty {
relation.tcx().sess.delay_span_bug(
DUMMY_SP,
- &format!("cannot relate constants of different types: {} != {}", a_ty, b_ty),
+ &format!(
+ "cannot relate constants ({:?}, {:?}) of different types: {} != {}",
+ a, b, a_ty, b_ty
+ ),
);
}
@@ -602,11 +626,16 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
// an unnormalized (i.e. unevaluated) const in the param-env.
// FIXME(generic_const_exprs): Once we always lazily unify unevaluated constants
// these `eval` calls can be removed.
- if !relation.tcx().features().generic_const_exprs {
+ if !tcx.features().generic_const_exprs {
a = a.eval(tcx, relation.param_env());
b = b.eval(tcx, relation.param_env());
}
+ if tcx.features().generic_const_exprs {
+ a = tcx.expand_abstract_consts(a);
+ b = tcx.expand_abstract_consts(b);
+ }
+
// Currently, the values that can be unified are primitive types,
// and those that derive both `PartialEq` and `Eq`, corresponding
// to structural-match types.
@@ -623,33 +652,69 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
- (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
- if tcx.features().generic_const_exprs =>
- {
- tcx.try_unify_abstract_consts(relation.param_env().and((au, bu)))
- }
-
// While this is slightly incorrect, it shouldn't matter for `min_const_generics`
// and is the better alternative to waiting until `generic_const_exprs` can
// be stabilized.
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => {
+ assert_eq!(a.ty(), b.ty());
let substs = relation.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
au.substs,
bu.substs,
)?;
- return Ok(tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def: au.def, substs }),
- ty: a.ty(),
- }));
+ return Ok(tcx.mk_const(ty::UnevaluatedConst { def: au.def, substs }, a.ty()));
+ }
+ // Before calling relate on exprs, it is necessary to ensure that the nested consts
+ // have identical types.
+ (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => {
+ let r = relation;
+
+ // FIXME(generic_const_exprs): is it possible to relate two consts which are not identical
+ // exprs? Should we care about that?
+ let expr = match (ae, be) {
+ (Expr::Binop(a_op, al, ar), Expr::Binop(b_op, bl, br))
+ if a_op == b_op && al.ty() == bl.ty() && ar.ty() == br.ty() =>
+ {
+ Expr::Binop(a_op, r.consts(al, bl)?, r.consts(ar, br)?)
+ }
+ (Expr::UnOp(a_op, av), Expr::UnOp(b_op, bv))
+ if a_op == b_op && av.ty() == bv.ty() =>
+ {
+ Expr::UnOp(a_op, r.consts(av, bv)?)
+ }
+ (Expr::Cast(ak, av, at), Expr::Cast(bk, bv, bt))
+ if ak == bk && av.ty() == bv.ty() =>
+ {
+ Expr::Cast(ak, r.consts(av, bv)?, r.tys(at, bt)?)
+ }
+ (Expr::FunctionCall(af, aa), Expr::FunctionCall(bf, ba))
+ if aa.len() == ba.len()
+ && af.ty() == bf.ty()
+ && aa
+ .iter()
+ .zip(ba.iter())
+ .all(|(a_arg, b_arg)| a_arg.ty() == b_arg.ty()) =>
+ {
+ let func = r.consts(af, bf)?;
+ let mut related_args = Vec::with_capacity(aa.len());
+ for (a_arg, b_arg) in aa.iter().zip(ba.iter()) {
+ related_args.push(r.consts(a_arg, b_arg)?);
+ }
+ let related_args = tcx.mk_const_list(related_args.iter());
+ Expr::FunctionCall(func, related_args)
+ }
+ _ => return Err(TypeError::ConstMismatch(expected_found(r, a, b))),
+ };
+ let kind = ty::ConstKind::Expr(expr);
+ return Ok(tcx.mk_const(kind, a.ty()));
}
_ => false,
};
if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) }
}
-impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
+impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
a: Self,