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:
commit
78ff609d73
29 changed files with 554 additions and 277 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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>),
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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>>,
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
17
src/test/ui/nll/user-annotations/cast_static_lifetime.rs
Normal file
17
src/test/ui/nll/user-annotations/cast_static_lifetime.rs
Normal 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;
|
||||
}
|
13
src/test/ui/nll/user-annotations/cast_static_lifetime.stderr
Normal file
13
src/test/ui/nll/user-annotations/cast_static_lifetime.stderr
Normal 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`.
|
|
@ -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() {
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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() {
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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() {
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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() {
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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() {
|
||||
}
|
|
@ -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
|
||||
|
13
src/test/ui/nll/user-annotations/normalization.rs
Normal file
13
src/test/ui/nll/user-annotations/normalization.rs
Normal 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
|
||||
}
|
13
src/test/ui/nll/user-annotations/normalization.stderr
Normal file
13
src/test/ui/nll/user-annotations/normalization.stderr
Normal 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`.
|
25
src/test/ui/nll/user-annotations/normalize-self-ty.rs
Normal file
25
src/test/ui/nll/user-annotations/normalize-self-ty.rs
Normal 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);
|
||||
}
|
Loading…
Add table
Reference in a new issue