Skip to content
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

fix let _: ty = expr subtyping error #93856

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion compiler/rustc_borrowck/src/constraint_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
fn visit_ascribe_user_ty(
&mut self,
_place: &Place<'tcx>,
_variance: &ty::Variance,
_user_ty: &UserTypeProjection,
_location: Location,
) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/renumber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};

/// Replaces all free regions appearing in the MIR with fresh
/// inference variables, returning the number of variables created.
/// inference variables.
#[instrument(skip(infcx, body, promoted), level = "debug")]
pub fn renumber_mir<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
Expand Down
19 changes: 10 additions & 9 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,6 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
if let Some(annotation_index) = constant.user_ty {
if let Err(terr) = self.cx.relate_type_and_user_type(
constant.literal.ty(),
ty::Variance::Invariant,
&UserTypeProjection { base: annotation_index, projs: vec![] },
location.to_locations(),
ConstraintCategory::Boring,
Expand Down Expand Up @@ -425,6 +424,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
ConstraintCategory::Boring,
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
constant.literal.ty(),
ty::Variance::Invariant,
uv.def.did,
UserSubsts { substs: uv.substs, user_self_ty: None },
)),
Expand Down Expand Up @@ -492,7 +492,6 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {

if let Err(terr) = self.cx.relate_type_and_user_type(
ty,
ty::Variance::Invariant,
user_ty,
Locations::All(*span),
ConstraintCategory::TypeAnnotation,
Expand Down Expand Up @@ -1068,15 +1067,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.user_type_annotations
);
for user_annotation in self.user_type_annotations {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty, variance } =
*user_annotation;
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
match annotation {
UserType::Ty(mut ty) => {
lcnr marked this conversation as resolved.
Show resolved Hide resolved
ty = self.normalize(ty, Locations::All(span));

if let Err(terr) = self.eq_types(
// `ty` and `inferred_ty` are swapped for
// better diagnostics.
if let Err(terr) = self.relate_types(
lcnr marked this conversation as resolved.
Show resolved Hide resolved
ty,
variance.xform(ty::Variance::Contravariant),
inferred_ty,
Locations::All(span),
ConstraintCategory::BoringNoLocation,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to remember why we chose to use "type equality" here. I have a vague memory that there was a reason, but it seems there aren't any failing tests, at least.

Expand Down Expand Up @@ -1104,6 +1107,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::BoringNoLocation,
self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
inferred_ty,
variance,
def_id,
user_substs,
)),
Expand Down Expand Up @@ -1174,7 +1178,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
fn relate_type_and_user_type(
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
user_ty: &UserTypeProjection,
locations: Locations,
category: ConstraintCategory,
Expand Down Expand Up @@ -1202,7 +1205,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);

let ty = curr_projected_ty.ty;
self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?;
self.relate_types(ty, ty::Variance::Invariant, a, locations, category)?;

Ok(())
}
Expand Down Expand Up @@ -1397,7 +1400,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if let Some(annotation_index) = self.rvalue_user_ty(rv) {
if let Err(terr) = self.relate_type_and_user_type(
rv_ty,
ty::Variance::Invariant,
&UserTypeProjection { base: annotation_index, projs: vec![] },
location.to_locations(),
ConstraintCategory::Boring,
Expand Down Expand Up @@ -1449,11 +1451,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
};
}
StatementKind::AscribeUserType(box (ref place, ref projection), variance) => {
StatementKind::AscribeUserType(box (ref place, ref projection)) => {
let place_ty = place.ty(body, tcx).ty;
if let Err(terr) = self.relate_type_and_user_type(
place_ty,
variance,
projection,
Locations::All(stmt.source_info.span),
ConstraintCategory::TypeAnnotation,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Retag(_, _)
| StatementKind::AscribeUserType(_, _)
| StatementKind::AscribeUserType(_)
| StatementKind::Coverage(_)
| StatementKind::Nop => {}
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1581,7 +1581,7 @@ pub enum StatementKind<'tcx> {
/// - `Contravariant` -- requires that `T_y :> T`
/// - `Invariant` -- requires that `T_y == T`
/// - `Bivariant` -- no effect
AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>),

/// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A
/// `Coverage` statement carries metadata about the coverage region, used to inject a coverage
Expand Down Expand Up @@ -1705,8 +1705,8 @@ impl Debug for Statement<'_> {
SetDiscriminant { ref place, variant_index } => {
write!(fmt, "discriminant({:?}) = {:?}", place, variant_index)
}
AscribeUserType(box (ref place, ref c_ty), ref variance) => {
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
AscribeUserType(box (ref place, ref c_ty)) => {
write!(fmt, "AscribeUserType({:?}, {:?})", place, c_ty)
}
Coverage(box self::Coverage { ref kind, code_region: Some(ref rgn) }) => {
write!(fmt, "Coverage::{:?} for {:?}", kind, rgn)
Expand Down
7 changes: 2 additions & 5 deletions compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,9 @@ macro_rules! make_mir_visitor {

fn visit_ascribe_user_ty(&mut self,
place: & $($mutability)? Place<'tcx>,
variance: & $($mutability)? ty::Variance,
user_ty: & $($mutability)? UserTypeProjection,
location: Location) {
self.super_ascribe_user_ty(place, variance, user_ty, location);
self.super_ascribe_user_ty(place, user_ty, location);
}

fn visit_coverage(&mut self,
Expand Down Expand Up @@ -413,9 +412,8 @@ macro_rules! make_mir_visitor {
}
StatementKind::AscribeUserType(
box(ref $($mutability)? place, ref $($mutability)? user_ty),
variance
) => {
self.visit_ascribe_user_ty(place, variance, user_ty, location);
self.visit_ascribe_user_ty(place, user_ty, location);
}
StatementKind::Coverage(coverage) => {
self.visit_coverage(
Expand Down Expand Up @@ -775,7 +773,6 @@ macro_rules! make_mir_visitor {

fn super_ascribe_user_ty(&mut self,
place: & $($mutability)? Place<'tcx>,
_variance: & $($mutability)? ty::Variance,
user_ty: & $($mutability)? UserTypeProjection,
location: Location) {
self.visit_place(
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,14 +552,16 @@ impl<'tcx> PatTyProj<'tcx> {
pub fn user_ty(
self,
annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
inferred_ty: Ty<'tcx>,
span: Span,
inferred_ty: Ty<'tcx>,
variance: ty::Variance,
) -> UserTypeProjection {
UserTypeProjection {
base: annotations.push(CanonicalUserTypeAnnotation {
span,
user_ty: self.user_ty,
inferred_ty,
variance,
}),
projs: Vec::new(),
}
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_middle/src/traits/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,26 @@ use std::mem;
pub mod type_op {
use crate::ty::fold::TypeFoldable;
use crate::ty::subst::UserSubsts;
use crate::ty::{Predicate, Ty};
use crate::ty::{self, Predicate, Ty};
use rustc_hir::def_id::DefId;
use std::fmt;

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct AscribeUserType<'tcx> {
pub mir_ty: Ty<'tcx>,
pub variance: ty::Variance,
pub def_id: DefId,
pub user_substs: UserSubsts<'tcx>,
}

impl<'tcx> AscribeUserType<'tcx> {
pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self {
Self { mir_ty, def_id, user_substs }
pub fn new(
mir_ty: Ty<'tcx>,
variance: ty::Variance,
def_id: DefId,
user_substs: UserSubsts<'tcx>,
) -> Self {
Self { mir_ty, variance, def_id, user_substs }
}
}

Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::ty::{
FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region,
RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
Variance,
};
use rustc_ast as ast;
use rustc_attr as attr;
Expand Down Expand Up @@ -833,6 +834,13 @@ pub struct CanonicalUserTypeAnnotation<'tcx> {
pub user_ty: CanonicalUserType<'tcx>,
pub span: Span,
pub inferred_ty: Ty<'tcx>,
/// The variance relation inferred type and the user type.
///
/// If this is covariant, then `inferred_ty` has to be a subtype of `user_ty`.
///
/// As the variance is already applied from `user_ty` to `inferred_ty`, all
/// other uses of `inferred_ty` should be invariant.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have a comment explaining:

let x: T = ...; // invariant
let _: T = ...; // covariant

pub variance: Variance,
nikomatsakis marked this conversation as resolved.
Show resolved Hide resolved
}

/// Canonicalized user type annotation.
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_build/src/build/expr/as_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::build::Builder;
use rustc_middle::mir::interpret::{ConstValue, Scalar};
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
use rustc_middle::ty::{CanonicalUserTypeAnnotation, Variance};

impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, yielding a compile-time constant. Assumes that
Expand All @@ -22,6 +22,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span,
user_ty,
inferred_ty: ty,
variance: Variance::Invariant,
})
});
assert_eq!(literal.ty(), ty);
Expand Down
24 changes: 10 additions & 14 deletions compiler/rustc_mir_build/src/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,20 +493,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span: source_info.span,
user_ty,
inferred_ty: expr.ty,
variance: Variance::Invariant,
});

let place = place_builder.clone().into_place(this.tcx, this.typeck_results);
this.cfg.push(
block,
Statement {
source_info,
kind: StatementKind::AscribeUserType(
Box::new((
place,
UserTypeProjection { base: annotation_index, projs: vec![] },
)),
Variance::Invariant,
),
kind: StatementKind::AscribeUserType(Box::new((
place,
UserTypeProjection { base: annotation_index, projs: vec![] },
))),
},
);
}
Expand All @@ -522,18 +520,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span: source_info.span,
user_ty,
inferred_ty: expr.ty,
variance: Variance::Invariant,
});
this.cfg.push(
block,
Statement {
source_info,
kind: StatementKind::AscribeUserType(
Box::new((
Place::from(temp),
UserTypeProjection { base: annotation_index, projs: vec![] },
)),
Variance::Invariant,
),
kind: StatementKind::AscribeUserType(Box::new((
Place::from(temp),
UserTypeProjection { base: annotation_index, projs: vec![] },
))),
},
);
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_build/src/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Variance};
use std::iter;

impl<'a, 'tcx> Builder<'a, 'tcx> {
Expand Down Expand Up @@ -364,6 +364,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span: source_info.span,
user_ty: ty,
inferred_ty,
variance: Variance::Invariant,
})
});
let adt = Box::new(AggregateKind::Adt(
Expand Down
33 changes: 8 additions & 25 deletions compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use rustc_index::bit_set::BitSet;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
use rustc_middle::thir::{self, *};
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, Variance};
use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, Pos, Span};
use rustc_target::abi::VariantIdx;
Expand Down Expand Up @@ -538,31 +538,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let ty_source_info = self.source_info(user_ty_span);
let user_ty = pat_ascription_ty.user_ty(
&mut self.canonical_user_type_annotations,
place.ty(&self.local_decls, self.tcx).ty,
ty_source_info.span,
place.ty(&self.local_decls, self.tcx).ty,
Variance::Invariant,
);
self.cfg.push(
block,
Statement {
source_info: ty_source_info,
kind: StatementKind::AscribeUserType(
Box::new((place, user_ty)),
// We always use invariant as the variance here. This is because the
// variance field from the ascription refers to the variance to use
// when applying the type to the value being matched, but this
// ascription applies rather to the type of the binding. e.g., in this
// example:
//
// ```
// let x: T = <expr>
// ```
//
// We are creating an ascription that defines the type of `x` to be
// exactly `T` (i.e., with invariance). The variance field, in
// contrast, is intended to be used to relate `T` to the type of
// `<expr>`.
ty::Variance::Invariant,
),
kind: StatementKind::AscribeUserType(Box::new((place, user_ty))),
},
);

Expand Down Expand Up @@ -796,6 +780,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span: user_ty_span,
user_ty: user_ty.user_ty,
inferred_ty: subpattern.ty,
variance: Variance::Invariant,
};
let projection = UserTypeProjection {
base: self.canonical_user_type_annotations.push(annotation),
Expand Down Expand Up @@ -2076,17 +2061,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

let user_ty = ascription.user_ty.user_ty(
&mut self.canonical_user_type_annotations,
ascription.source.ty(&self.local_decls, self.tcx).ty,
source_info.span,
ascription.source.ty(&self.local_decls, self.tcx).ty,
ascription.variance,
nikomatsakis marked this conversation as resolved.
Show resolved Hide resolved
);
self.cfg.push(
block,
Statement {
source_info,
kind: StatementKind::AscribeUserType(
Box::new((ascription.source, user_ty)),
ascription.variance,
),
kind: StatementKind::AscribeUserType(Box::new((ascription.source, user_ty))),
},
);
}
Expand Down
Loading