Auto merge of #55152 - nikomatsakis:nll-issue-54571-type-annot-in-constants, r=pnkfelix

support type annot in constants, casts

Fixes #54571
Fixes #54332
Fixes #55183

r? @pnkfelix
This commit is contained in:
bors 2018-10-19 20:20:12 +00:00
commit 78ff609d73
29 changed files with 554 additions and 277 deletions

View file

@ -597,11 +597,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::UserTypeAnnotation<
mir::UserTypeAnnotation::Ty(ref ty) => {
ty.hash_stable(hcx, hasher);
}
mir::UserTypeAnnotation::FnDef(ref def_id, ref substs) => {
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
}
mir::UserTypeAnnotation::AdtDef(ref def_id, ref substs) => {
mir::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => {
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
}

View file

@ -19,7 +19,7 @@
use infer::canonical::substitute::substitute_value;
use infer::canonical::{
Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResponse, Certainty,
Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty,
OriginalQueryValues, QueryRegionConstraint, QueryResponse,
};
use infer::region_constraints::{Constraint, RegionConstraintData};
@ -262,13 +262,6 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
where
R: Debug + TypeFoldable<'tcx>,
{
// In an NLL query, there should be no type variables in the
// query, only region variables.
debug_assert!(query_response.variables.iter().all(|v| match v.kind {
CanonicalVarKind::Ty(_) => false,
CanonicalVarKind::Region => true,
}));
let result_subst =
self.query_response_substitution_guess(cause, original_values, query_response);

View file

@ -149,7 +149,7 @@ pub struct Verify<'tcx> {
pub bound: VerifyBound<'tcx>,
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum GenericKind<'tcx> {
Param(ty::ParamTy),
Projection(ty::ProjectionTy<'tcx>),

View file

@ -2425,15 +2425,16 @@ pub struct Constant<'tcx> {
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum UserTypeAnnotation<'tcx> {
Ty(CanonicalTy<'tcx>),
FnDef(DefId, CanonicalUserSubsts<'tcx>),
AdtDef(&'tcx AdtDef, CanonicalUserSubsts<'tcx>),
/// The canonical type is the result of `type_of(def_id)` with the
/// given substitutions applied.
TypeOf(DefId, CanonicalUserSubsts<'tcx>),
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> {
(UserTypeAnnotation::Ty)(ty),
(UserTypeAnnotation::FnDef)(def, substs),
(UserTypeAnnotation::AdtDef)(def, substs),
(UserTypeAnnotation::TypeOf)(def, substs),
}
}

View file

@ -25,7 +25,7 @@ use rustc::mir::{
use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
use rustc::util::common;
use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::scc::Sccs;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_errors::{Diagnostic, DiagnosticBuilder};
@ -67,10 +67,8 @@ pub struct RegionInferenceContext<'tcx> {
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
/// Map closure bounds to a `Span` that should be used for error reporting.
closure_bounds_mapping: FxHashMap<
Location,
FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
>,
closure_bounds_mapping:
FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
/// Contains the minimum universe of any variable within the same
/// SCC. We will ensure that no SCC contains values that are not
@ -580,6 +578,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
) {
let tcx = infcx.tcx;
// Sometimes we register equivalent type-tests that would
// result in basically the exact same error being reported to
// the user. Avoid that.
let mut deduplicate_errors = FxHashSet::default();
for type_test in &self.type_tests {
debug!("check_type_test: {:?}", type_test);
@ -605,11 +608,31 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}
// Oh the humanity. Obviously we will do better than this error eventually.
// Type-test failed. Report the error.
// Try to convert the lower-bound region into something named we can print for the user.
let lower_bound_region = self.to_error_region(type_test.lower_bound);
// Skip duplicate-ish errors.
let type_test_span = type_test.locations.span(mir);
let erased_generic_kind = tcx.erase_regions(&type_test.generic_kind);
if !deduplicate_errors.insert((
erased_generic_kind,
lower_bound_region,
type_test.locations,
)) {
continue;
} else {
debug!(
"check_type_test: reporting error for erased_generic_kind={:?}, \
lower_bound_region={:?}, \
type_test.locations={:?}",
erased_generic_kind, lower_bound_region, type_test.locations,
);
}
if let Some(lower_bound_region) = lower_bound_region {
let region_scope_tree = &tcx.region_scope_tree(mir_def_id);
let type_test_span = type_test.locations.span(mir);
infcx
.construct_generic_bound_failure(
region_scope_tree,
@ -629,7 +652,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// to report it; we could probably handle it by
// iterating over the universal regions and reporting
// an error that multiple bounds are required.
let type_test_span = type_test.locations.span(mir);
tcx.sess
.struct_span_err(
type_test_span,

View file

@ -142,6 +142,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
}
fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
debug!("add_type_test(type_test={:?})", type_test);
self.type_tests.push(type_test);
}
}

View file

@ -42,7 +42,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp;
use rustc::traits::query::{Fallible, NoSolution};
use rustc::traits::{ObligationCause, PredicateObligations};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::{Subst, Substs, UnpackedKind};
use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSelfTy, UserSubsts};
use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
use std::rc::Rc;
use std::{fmt, iter};
@ -753,10 +753,8 @@ crate struct MirTypeckRegionConstraints<'tcx> {
crate outlives_constraints: ConstraintSet,
crate closure_bounds_mapping: FxHashMap<
Location,
FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
>,
crate closure_bounds_mapping:
FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
crate type_tests: Vec<TypeTest<'tcx>>,
}
@ -866,7 +864,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
&mut self,
locations: Locations,
category: ConstraintCategory,
op: impl type_op::TypeOp<'gcx, 'tcx, Output=R>,
op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>,
) -> Fallible<R> {
let (r, opt_data) = op.fully_perform(self.infcx)?;
@ -903,6 +901,27 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
}
/// Convenient wrapper around `relate_tys::relate_types` -- see
/// that fn for docs.
fn relate_types(
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
relate_tys::relate_types(
self.infcx,
a,
v,
b,
locations,
category,
self.borrowck_context.as_mut().map(|x| &mut **x),
)
}
fn sub_types(
&mut self,
sub: Ty<'tcx>,
@ -910,14 +929,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
relate_tys::sub_types(
self.infcx,
sub,
sup,
locations,
category,
self.borrowck_context.as_mut().map(|x| &mut **x),
)
self.relate_types(sub, ty::Variance::Covariant, sup, locations, category)
}
/// Try to relate `sub <: sup`; if this fails, instantiate opaque
@ -952,41 +964,133 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
relate_tys::eq_types(
self.infcx,
a,
b,
locations,
category,
self.borrowck_context.as_mut().map(|x| &mut **x),
)
self.relate_types(a, ty::Variance::Invariant, b, locations, category)
}
fn relate_type_and_user_type(
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
b: UserTypeAnnotation<'tcx>,
user_ty: UserTypeAnnotation<'tcx>,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
let ty = relate_tys::relate_type_and_user_type(
self.infcx,
a,
v,
b,
locations,
category,
self.borrowck_context.as_mut().map(|x| &mut **x),
)?;
self.prove_predicate(
ty::Predicate::WellFormed(ty),
locations,
category,
let tcx = self.tcx();
debug!(
"relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})",
a, v, user_ty, locations
);
// The `TypeRelating` code assumes that "unresolved inference
// variables" appear in the "a" side, so flip `Contravariant`
// ambient variance to get the right relationship.
let v1 = ty::Contravariant.xform(v);
match user_ty {
UserTypeAnnotation::Ty(canonical_ty) => {
let (ty, _) = self.infcx
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
self.relate_types(ty, v1, a, locations, category)?;
self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category);
}
UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
let (
UserSubsts {
substs,
user_self_ty,
},
_,
) = self.infcx
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
let ty = self.tcx().type_of(def_id);
let ty = ty.subst(tcx, substs);
let ty = self.normalize(ty, locations);
self.relate_types(ty, v1, a, locations, category)?;
if let Some(UserSelfTy {
impl_def_id,
self_ty,
}) = user_self_ty
{
let impl_self_ty = tcx.type_of(impl_def_id);
let impl_self_ty = impl_self_ty.subst(tcx, &substs);
let impl_self_ty = self.normalize(impl_self_ty, locations);
// There may be type variables in `substs` and hence
// in `impl_self_ty`, but they should all have been
// resolved to some fixed value during the first call
// to `relate`, above. Therefore, if we use
// `resolve_type_vars_if_possible` we should get to
// something without type variables. This is important
// because the `b` type in `relate_with_variance`
// below is not permitted to have inference variables.
let impl_self_ty = self.infcx.resolve_type_vars_if_possible(&impl_self_ty);
assert!(!impl_self_ty.has_infer_types());
self.eq_types(self_ty, impl_self_ty, locations, category)?;
}
// Prove the predicates coming along with `def_id`.
//
// Also, normalize the `instantiated_predicates`
// because otherwise we wind up with duplicate "type
// outlives" error messages.
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
let instantiated_predicates = self.fold_to_region_vid(instantiated_predicates);
self.normalize_and_prove_instantiated_predicates(
instantiated_predicates,
locations,
);
// In addition to proving the predicates, we have to
// prove that `ty` is well-formed -- this is because
// the WF of `ty` is predicated on the substs being
// well-formed, and we haven't proven *that*. We don't
// want to prove the WF of types from `substs` directly because they
// haven't been normalized.
//
// FIXME(nmatsakis): Well, perhaps we should normalize
// them? This would only be relevant if some input
// type were ill-formed but did not appear in `ty`,
// which...could happen with normalization...
self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category);
}
}
Ok(())
}
/// Replace all free regions in `value` with their NLL `RegionVid`
/// equivalents; if not in NLL, does nothing. This is never
/// particularly necessary -- we'll do it lazilly as we process
/// the value anyway -- but in some specific cases it is useful to
/// normalize so we can suppress duplicate error messages.
fn fold_to_region_vid<T>(
&self,
value: T
) -> T
where T: TypeFoldable<'tcx>
{
if let Some(borrowck_context) = &self.borrowck_context {
self.tcx().fold_regions(&value, &mut false, |r, _debruijn| {
if r.has_free_regions() {
self.tcx().mk_region(ty::RegionKind::ReVar(
borrowck_context.universal_regions.to_region_vid(r),
))
} else {
r
}
})
} else {
value
}
}
fn eq_opaque_type_and_type(
&mut self,
revealed_ty: Ty<'tcx>,
@ -1115,9 +1219,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
let place_ty = place.ty(mir, tcx).to_ty(tcx);
let rv_ty = rv.ty(mir, tcx);
if let Err(terr) =
self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
{
span_mirbug!(
self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
{
span_mirbug!(
self,
stmt,
"bad assignment ({:?} = {:?}): {:?}",
@ -1125,7 +1229,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
rv_ty,
terr
);
}
}
if let Some(user_ty) = self.rvalue_user_ty(rv) {
if let Err(terr) = self.relate_type_and_user_type(
@ -1245,9 +1349,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
let locations = term_location.to_locations();
if let Err(terr) =
self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
{
span_mirbug!(
self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
{
span_mirbug!(
self,
term,
"bad DropAndReplace ({:?} = {:?}): {:?}",
@ -1255,7 +1359,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
rv_ty,
terr
);
}
}
}
TerminatorKind::SwitchInt {
ref discr,
@ -1399,9 +1503,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
let locations = term_location.to_locations();
if let Err(terr) =
self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
{
span_mirbug!(
self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
{
span_mirbug!(
self,
term,
"call dest mismatch ({:?} <- {:?}): {:?}",
@ -1409,7 +1513,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
sig.output(),
terr
);
}
}
// When `#![feature(unsized_locals)]` is not enabled,
// this check is done at `check_local`.
@ -2050,7 +2154,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
aggregate_kind, location
);
let instantiated_predicates = match aggregate_kind {
let instantiated_predicates = match aggregate_kind {
AggregateKind::Adt(def, _, substs, _, _) => {
tcx.predicates_of(def.did).instantiate(tcx, substs)
}
@ -2096,15 +2200,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
substs: &'tcx Substs<'tcx>,
location: Location,
) -> ty::InstantiatedPredicates<'tcx> {
if let Some(closure_region_requirements) =
tcx.mir_borrowck(def_id).closure_requirements
{
let closure_constraints = closure_region_requirements.apply_requirements(
tcx,
location,
def_id,
substs,
);
if let Some(closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements {
let closure_constraints =
closure_region_requirements.apply_requirements(tcx, location, def_id, substs);
if let Some(ref mut borrowck_context) = self.borrowck_context {
let bounds_mapping = closure_constraints
@ -2113,10 +2211,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
.filter_map(|(idx, constraint)| {
let ty::OutlivesPredicate(k1, r2) =
constraint.no_late_bound_regions().unwrap_or_else(|| {
bug!(
"query_constraint {:?} contained bound regions",
constraint,
);
bug!("query_constraint {:?} contained bound regions", constraint,);
});
match k1.unpack() {
@ -2124,8 +2219,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
// constraint is r1: r2
let r1_vid = borrowck_context.universal_regions.to_region_vid(r1);
let r2_vid = borrowck_context.universal_regions.to_region_vid(r2);
let outlives_requirements = &closure_region_requirements
.outlives_requirements[idx];
let outlives_requirements =
&closure_region_requirements.outlives_requirements[idx];
Some((
(r1_vid, r2_vid),
(
@ -2139,10 +2234,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
})
.collect();
let existing = borrowck_context.constraints
let existing = borrowck_context
.constraints
.closure_bounds_mapping
.insert(location, bounds_mapping);
assert!(existing.is_none(), "Multiple closures at the same location.");
assert!(
existing.is_none(),
"Multiple closures at the same location."
);
}
self.push_region_constraints(

View file

@ -12,35 +12,23 @@ use borrow_check::nll::constraints::OutlivesConstraint;
use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use rustc::mir::{ConstraintCategory, UserTypeAnnotation};
use rustc::mir::ConstraintCategory;
use rustc::traits::query::Fallible;
use rustc::ty::relate::TypeRelation;
use rustc::ty::subst::{Subst, UserSelfTy, UserSubsts};
use rustc::ty::{self, Ty, TypeFoldable};
use syntax_pos::DUMMY_SP;
use rustc::ty::{self, Ty};
/// Adds sufficient constraints to ensure that `a <: b`.
pub(super) fn sub_types<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
) -> Fallible<()> {
debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
TypeRelating::new(
infcx,
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
ty::Variance::Covariant,
).relate(&a, &b)?;
Ok(())
}
/// Adds sufficient constraints to ensure that `a == b`.
pub(super) fn eq_types<'tcx>(
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
///
/// - "Covariant" `a <: b`
/// - "Invariant" `a == b`
/// - "Contravariant" `a :> b`
///
/// NB. The type `a` is permitted to have unresolved inference
/// variables, but not the type `b`.
pub(super) fn relate_types<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: Ty<'tcx>,
v: ty::Variance,
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
@ -50,105 +38,11 @@ pub(super) fn eq_types<'tcx>(
TypeRelating::new(
infcx,
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
ty::Variance::Invariant,
v,
).relate(&a, &b)?;
Ok(())
}
/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
/// a user-given type (which means it may have canonical variables
/// encoding things like `_`).
pub(super) fn relate_type_and_user_type<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: Ty<'tcx>,
v: ty::Variance,
user_ty: UserTypeAnnotation<'tcx>,
locations: Locations,
category: ConstraintCategory,
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
) -> Fallible<Ty<'tcx>> {
debug!(
"relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})",
a, v, user_ty, locations
);
// The `TypeRelating` code assumes that the "canonical variables"
// appear in the "a" side, so flip `Contravariant` ambient
// variance to get the right relationship.
let v1 = ty::Contravariant.xform(v);
let mut type_relating = TypeRelating::new(
infcx,
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
v1,
);
match user_ty {
UserTypeAnnotation::Ty(canonical_ty) => {
let (ty, _) =
infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
type_relating.relate(&ty, &a)?;
Ok(ty)
}
UserTypeAnnotation::FnDef(def_id, canonical_substs) => {
let (
UserSubsts {
substs,
user_self_ty,
},
_,
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
let ty = infcx.tcx.mk_fn_def(def_id, substs);
type_relating.relate(&ty, &a)?;
if let Some(UserSelfTy {
impl_def_id,
self_ty,
}) = user_self_ty
{
let impl_self_ty = infcx.tcx.type_of(impl_def_id);
let impl_self_ty = impl_self_ty.subst(infcx.tcx, &substs);
// There may be type variables in `substs` and hence
// in `impl_self_ty`, but they should all have been
// resolved to some fixed value during the first call
// to `relate`, above. Therefore, if we use
// `resolve_type_vars_if_possible` we should get to
// something without type variables. This is important
// because the `b` type in `relate_with_variance`
// below is not permitted to have inference variables.
let impl_self_ty = infcx.resolve_type_vars_if_possible(&impl_self_ty);
assert!(!impl_self_ty.has_infer_types());
type_relating.relate_with_variance(
ty::Variance::Invariant,
&self_ty,
&impl_self_ty,
)?;
}
Ok(ty)
}
UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => {
let (
UserSubsts {
substs,
user_self_ty,
},
_,
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
// We don't extract adt-defs with a self-type.
assert!(user_self_ty.is_none());
let ty = infcx.tcx.mk_adt(adt_def, substs);
type_relating.relate(&ty, &a)?;
Ok(ty)
}
}
}
struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,

View file

@ -139,17 +139,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ExprKind::PlaceTypeAscription { source, user_ty } => {
let place = unpack!(block = this.as_place(block, source));
this.cfg.push(
block,
Statement {
source_info,
kind: StatementKind::AscribeUserType(
place.clone(),
Variance::Invariant,
user_ty,
),
},
);
if let Some(user_ty) = user_ty {
this.cfg.push(
block,
Statement {
source_info,
kind: StatementKind::AscribeUserType(
place.clone(),
Variance::Invariant,
user_ty,
),
},
);
}
block.and(place)
}
ExprKind::ValueTypeAscription { source, user_ty } => {
@ -157,17 +159,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let temp = unpack!(
block = this.as_temp(block, source.temp_lifetime, source, mutability)
);
this.cfg.push(
block,
Statement {
source_info,
kind: StatementKind::AscribeUserType(
Place::Local(temp.clone()),
Variance::Invariant,
user_ty,
),
},
);
if let Some(user_ty) = user_ty {
this.cfg.push(
block,
Statement {
source_info,
kind: StatementKind::AscribeUserType(
Place::Local(temp.clone()),
Variance::Invariant,
user_ty,
),
},
);
}
block.and(Place::Local(temp))
}

View file

@ -295,7 +295,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let substs = cx.tables().node_substs(fun.hir_id);
let user_ty = cx.tables().user_substs(fun.hir_id)
.map(|user_substs| UserTypeAnnotation::AdtDef(adt_def, user_substs));
.map(|user_substs| UserTypeAnnotation::TypeOf(adt_def.did, user_substs));
let field_refs = args.iter()
.enumerate()
@ -637,12 +637,25 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
name: Field::new(cx.tcx.field_index(expr.id, cx.tables)),
}
}
hir::ExprKind::Cast(ref source, _) => {
hir::ExprKind::Cast(ref source, ref cast_ty) => {
// Check for a user-given type annotation on this `cast`
let user_ty = cx.tables.user_provided_tys().get(cast_ty.hir_id)
.map(|&t| UserTypeAnnotation::Ty(t));
debug!(
"cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
expr,
cast_ty.hir_id,
user_ty,
);
// Check to see if this cast is a "coercion cast", where the cast is actually done
// using a coercion (or is a no-op).
if let Some(&TyCastKind::CoercionCast) = cx.tables()
.cast_kinds()
.get(source.hir_id) {
let cast = if let Some(&TyCastKind::CoercionCast) =
cx.tables()
.cast_kinds()
.get(source.hir_id)
{
// Convert the lexpr to a vexpr.
ExprKind::Use { source: source.to_ref() }
} else {
@ -679,24 +692,30 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
} else {
None
};
let source = if let Some((did, offset, ty)) = var {
let source = if let Some((did, offset, var_ty)) = var {
let mk_const = |literal| Expr {
temp_lifetime,
ty,
ty: var_ty,
span: expr.span,
kind: ExprKind::Literal { literal, user_ty: None },
}.to_ref();
let offset = mk_const(ty::Const::from_bits(
cx.tcx,
offset as u128,
cx.param_env.and(ty),
cx.param_env.and(var_ty),
));
match did {
Some(did) => {
// in case we are offsetting from a computed discriminant
// and not the beginning of discriminants (which is always `0`)
let substs = Substs::identity_for_item(cx.tcx(), did);
let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty));
let lhs = mk_const(ty::Const::unevaluated(
cx.tcx(),
did,
substs,
var_ty,
));
let bin = ExprKind::Binary {
op: BinOp::Add,
lhs,
@ -704,7 +723,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
};
Expr {
temp_lifetime,
ty,
ty: var_ty,
span: expr.span,
kind: bin,
}.to_ref()
@ -714,20 +733,33 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
} else {
source.to_ref()
};
ExprKind::Cast { source }
};
if let Some(user_ty) = user_ty {
// NOTE: Creating a new Expr and wrapping a Cast inside of it may be
// inefficient, revisit this when performance becomes an issue.
let cast_expr = Expr {
temp_lifetime,
ty: expr_ty,
span: expr.span,
kind: cast,
};
ExprKind::ValueTypeAscription {
source: cast_expr.to_ref(),
user_ty: Some(user_ty),
}
} else {
cast
}
}
hir::ExprKind::Type(ref source, ref ty) => {
let user_provided_tys = cx.tables.user_provided_tys();
let user_ty = UserTypeAnnotation::Ty(
*user_provided_tys
.get(ty.hir_id)
.expect(&format!(
"{:?} not found in user_provided_tys, source: {:?}",
ty,
source,
))
);
let user_ty = user_provided_tys
.get(ty.hir_id)
.map(|&c_ty| UserTypeAnnotation::Ty(c_ty));
if source.is_place_expr() {
ExprKind::PlaceTypeAscription {
source: source.to_ref(),
@ -771,12 +803,10 @@ fn user_substs_applied_to_def(
Def::Fn(_) |
Def::Method(_) |
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) =>
Some(UserTypeAnnotation::FnDef(def.def_id(), cx.tables().user_substs(hir_id)?)),
Def::Const(_def_id) |
Def::AssociatedConst(_def_id) =>
bug!("unimplemented"),
Def::VariantCtor(_, CtorKind::Fn) |
Def::Const(_) |
Def::AssociatedConst(_) =>
Some(UserTypeAnnotation::TypeOf(def.def_id(), cx.tables().user_substs(hir_id)?)),
// A unit struct/variant which is used as a value (e.g.,
// `None`). This has the type of the enum/struct that defines
@ -889,14 +919,17 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
},
Def::Const(def_id) |
Def::AssociatedConst(def_id) => ExprKind::Literal {
literal: ty::Const::unevaluated(
cx.tcx,
def_id,
substs,
cx.tables().node_id_to_type(expr.hir_id),
),
user_ty: None, // FIXME(#47184) -- user given type annot on constants
Def::AssociatedConst(def_id) => {
let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
ExprKind::Literal {
literal: ty::Const::unevaluated(
cx.tcx,
def_id,
substs,
cx.tables().node_id_to_type(expr.hir_id),
),
user_ty,
}
},
Def::StructCtor(def_id, CtorKind::Const) |

View file

@ -276,12 +276,12 @@ pub enum ExprKind<'tcx> {
PlaceTypeAscription {
source: ExprRef<'tcx>,
/// Type that the user gave to this expression
user_ty: UserTypeAnnotation<'tcx>,
user_ty: Option<UserTypeAnnotation<'tcx>>,
},
ValueTypeAscription {
source: ExprRef<'tcx>,
/// Type that the user gave to this expression
user_ty: UserTypeAnnotation<'tcx>,
user_ty: Option<UserTypeAnnotation<'tcx>>,
},
Closure {
closure_id: DefId,

View file

@ -23,7 +23,7 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
adt_def: &'tcx AdtDef,
) -> Option<UserTypeAnnotation<'tcx>> {
let user_substs = self.tables().user_substs(hir_id)?;
Some(UserTypeAnnotation::AdtDef(adt_def, user_substs))
Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs))
}
/// Looks up the type associated with this hir-id and applies the
@ -35,8 +35,8 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
) -> Option<UserTypeAnnotation<'tcx>> {
let user_substs = self.tables().user_substs(hir_id)?;
match &self.tables().node_id_to_type(hir_id).sty {
ty::Adt(adt_def, _) => Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)),
ty::FnDef(def_id, _) => Some(UserTypeAnnotation::FnDef(*def_id, user_substs)),
ty::Adt(adt_def, _) => Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs)),
ty::FnDef(def_id, _) => Some(UserTypeAnnotation::TypeOf(*def_id, user_substs)),
sty => bug!(
"sty: {:?} should not have user-substs {:?} recorded ",
sty,

View file

@ -2357,6 +2357,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
t
}
pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
let ty = self.to_ty(ast_ty);
// If the type given by the user has free regions, save it for
// later, since NLL would like to enforce those. Also pass in
// types that involve projections, since those can resolve to
// `'static` bounds (modulo #54940, which hopefully will be
// fixed by the time you see this comment, dear reader,
// although I have my doubts). Other sorts of things are
// already sufficiently enforced with erased regions. =)
if ty.has_free_regions() || ty.has_projections() {
let c_ty = self.infcx.canonicalize_response(&ty);
self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty);
}
ty
}
pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
match self.tables.borrow().node_types().get(id) {
Some(&t) => t,
@ -4153,7 +4171,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
hir::ExprKind::Cast(ref e, ref t) => {
// Find the type of `e`. Supply hints based on the type we are casting to,
// if appropriate.
let t_cast = self.to_ty(t);
let t_cast = self.to_ty_saving_user_provided_ty(t);
let t_cast = self.resolve_type_vars_if_possible(&t_cast);
let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
let t_cast = self.resolve_type_vars_if_possible(&t_cast);
@ -4176,10 +4194,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
hir::ExprKind::Type(ref e, ref t) => {
let ty = self.to_ty(&t);
let ty = self.to_ty_saving_user_provided_ty(&t);
self.check_expr_eq_type(&e, ty);
let c_ty = self.infcx.canonicalize_response(&ty);
self.tables.borrow_mut().user_provided_tys_mut().insert(t.hir_id, c_ty);
ty
}
hir::ExprKind::Array(ref args) => {

View file

@ -17,6 +17,6 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
fn main() {
println!("{}", FOO);
//~^ ERROR erroneous constant used
//~| E0080
//~^ ERROR
//~| ERROR
}

View file

@ -0,0 +1,17 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(warnings)]
#![feature(nll)]
fn main() {
let x = 22_u32;
let y: &u32 = (&x) as &'static u32;
}

View file

@ -0,0 +1,13 @@
error[E0597]: `x` does not live long enough
--> $DIR/cast_static_lifetime.rs:16:19
|
LL | let y: &u32 = (&x) as &'static u32;
| ^^^^ borrowed value does not live long enough
LL | }
| - `x` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.

View file

@ -0,0 +1,15 @@
#![feature(nll)]
struct Foo<'a> { x: &'a u32 }
impl<'a> Foo<'a> {
const C: &'a u32 = &22;
}
fn foo<'a>(_: &'a u32) -> &'static u32 {
<Foo<'a>>::C //~ ERROR
}
fn main() {
}

View file

@ -0,0 +1,10 @@
error: unsatisfied lifetime constraints
--> $DIR/constant-in-expr-inherent-1.rs:10:5
|
LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
LL | <Foo<'a>>::C //~ ERROR
| ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
error: aborting due to previous error

View file

@ -0,0 +1,24 @@
#![feature(nll)]
trait Mirror {
type Me;
}
impl<T> Mirror for T {
type Me = T;
}
trait Foo<'a> {
const C: <&'a u32 as Mirror>::Me;
}
impl<'a, T> Foo<'a> for T {
const C: &'a u32 = &22;
}
fn foo<'a>(_: &'a u32) -> &'static u32 {
<() as Foo<'a>>::C //~ ERROR
}
fn main() {
}

View file

@ -0,0 +1,10 @@
error: unsatisfied lifetime constraints
--> $DIR/constant-in-expr-normalize.rs:20:5
|
LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
LL | <() as Foo<'a>>::C //~ ERROR
| ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
error: aborting due to previous error

View file

@ -0,0 +1,16 @@
#![feature(nll)]
trait Foo<'a> {
const C: &'a u32;
}
impl<'a, T> Foo<'a> for T {
const C: &'a u32 = &22;
}
fn foo<'a>(_: &'a u32) -> &'static u32 {
<() as Foo<'a>>::C //~ ERROR
}
fn main() {
}

View file

@ -0,0 +1,10 @@
error: unsatisfied lifetime constraints
--> $DIR/constant-in-expr-trait-item-1.rs:12:5
|
LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
LL | <() as Foo<'a>>::C //~ ERROR
| ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
error: aborting due to previous error

View file

@ -0,0 +1,16 @@
#![feature(nll)]
trait Foo<'a> {
const C: &'a u32;
}
impl<'a, T> Foo<'a> for T {
const C: &'a u32 = &22;
}
fn foo<'a, T: Foo<'a>>() -> &'static u32 {
<T as Foo<'a>>::C //~ ERROR
}
fn main() {
}

View file

@ -0,0 +1,10 @@
error: unsatisfied lifetime constraints
--> $DIR/constant-in-expr-trait-item-2.rs:12:5
|
LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
| -- lifetime `'a` defined here
LL | <T as Foo<'a>>::C //~ ERROR
| ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
error: aborting due to previous error

View file

@ -0,0 +1,16 @@
#![feature(nll)]
trait Foo<'a> {
const C: &'a u32;
}
impl<'a, T> Foo<'a> for T {
const C: &'a u32 = &22;
}
fn foo<'a, T: Foo<'a>>() -> &'static u32 {
T::C //~ ERROR
}
fn main() {
}

View file

@ -0,0 +1,10 @@
error: unsatisfied lifetime constraints
--> $DIR/constant-in-expr-trait-item-3.rs:12:5
|
LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
| -- lifetime `'a` defined here
LL | T::C //~ ERROR
| ^^^^ returning this value requires that `'a` must outlive `'static`
error: aborting due to previous error

View file

@ -0,0 +1,13 @@
// Test that we enforce a `&'static` requirement that is only visible
// after normalization.
#![feature(nll)]
#![ignore(unused)]
trait Foo { type Out; }
impl Foo for () { type Out = &'static u32; }
fn main() {
let a = 22;
let b: <() as Foo>::Out = &a; //~ ERROR
}

View file

@ -0,0 +1,13 @@
error[E0597]: `a` does not live long enough
--> $DIR/normalization.rs:12:31
|
LL | let b: <() as Foo>::Out = &a; //~ ERROR
| ^^ borrowed value does not live long enough
LL | }
| - `a` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.

View file

@ -0,0 +1,25 @@
// Regression test for #55183: check a case where the self type from
// the inherent impl requires normalization to be equal to the
// user-provided type.
//
// run-pass
#![feature(nll)]
trait Mirror {
type Me;
}
impl<T> Mirror for T {
type Me = T;
}
struct Foo<A, B>(A, B);
impl<A> Foo<A, <A as Mirror>::Me> {
fn m(b: A) { }
}
fn main() {
<Foo<&'static u32, &u32>>::m(&22);
}