mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
make ascribe_user_type a TypeOp
Projection types in user annotations may contain inference variables. This makes the normalization depend on the unification with the actual type and thus requires a separate TypeOp to track the obligations. Otherwise simply calling `TypeChecker::normalize` would ICE with "unexpected ambiguity"
This commit is contained in:
parent
37b40e471a
commit
c6a17bf8bc
@ -1,13 +1,13 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use rustc_infer::infer::canonical::Canonical;
|
use rustc_infer::infer::{canonical::Canonical, InferOk};
|
||||||
use rustc_infer::traits::query::NoSolution;
|
|
||||||
use rustc_middle::mir::ConstraintCategory;
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
|
use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
|
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
|
||||||
use rustc_trait_selection::traits::query::Fallible;
|
use rustc_trait_selection::traits::query::{Fallible, NoSolution};
|
||||||
|
use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
|
||||||
|
|
||||||
use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
|
use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
|
||||||
|
|
||||||
@ -177,4 +177,74 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||||||
value
|
value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
pub(super) fn ascribe_user_type(
|
||||||
|
&mut self,
|
||||||
|
mir_ty: Ty<'tcx>,
|
||||||
|
user_ty: ty::UserType<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
|
// FIXME: Ideally MIR types are normalized, but this is not always true.
|
||||||
|
let mir_ty = self.normalize(mir_ty, Locations::All(span));
|
||||||
|
|
||||||
|
self.fully_perform_op(
|
||||||
|
Locations::All(span),
|
||||||
|
ConstraintCategory::Boring,
|
||||||
|
self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)),
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
span_mirbug!(
|
||||||
|
self,
|
||||||
|
span,
|
||||||
|
"ascribe_user_type `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`.
|
||||||
|
///
|
||||||
|
/// FIXME(#104478, #104477): This is a hack for backward-compatibility.
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
pub(super) fn ascribe_user_type_skip_wf(
|
||||||
|
&mut self,
|
||||||
|
mir_ty: Ty<'tcx>,
|
||||||
|
user_ty: ty::UserType<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
|
let ty::UserType::Ty(user_ty) = user_ty else { bug!() };
|
||||||
|
|
||||||
|
// A fast path for a common case with closure input/output types.
|
||||||
|
if let ty::Infer(_) = user_ty.kind() {
|
||||||
|
self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring)
|
||||||
|
.unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mir_ty = self.normalize(mir_ty, Locations::All(span));
|
||||||
|
let cause = ObligationCause::dummy_with_span(span);
|
||||||
|
let param_env = self.param_env;
|
||||||
|
let op = |infcx: &'_ _| {
|
||||||
|
let ocx = ObligationCtxt::new_in_snapshot(infcx);
|
||||||
|
let user_ty = ocx.normalize(&cause, param_env, user_ty);
|
||||||
|
ocx.eq(&cause, param_env, user_ty, mir_ty)?;
|
||||||
|
if !ocx.select_all_or_error().is_empty() {
|
||||||
|
return Err(NoSolution);
|
||||||
|
}
|
||||||
|
Ok(InferOk { value: (), obligations: vec![] })
|
||||||
|
};
|
||||||
|
|
||||||
|
self.fully_perform_op(
|
||||||
|
Locations::All(span),
|
||||||
|
ConstraintCategory::Boring,
|
||||||
|
type_op::custom::CustomTypeOp::new(op, || "ascribe_user_type_skip_wf".to_string()),
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
span_mirbug!(
|
||||||
|
self,
|
||||||
|
span,
|
||||||
|
"ascribe_user_type_skip_wf `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use crate::universal_regions::UniversalRegions;
|
use crate::universal_regions::UniversalRegions;
|
||||||
@ -18,6 +18,52 @@ use crate::universal_regions::UniversalRegions;
|
|||||||
use super::{Locations, TypeChecker};
|
use super::{Locations, TypeChecker};
|
||||||
|
|
||||||
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
|
/// Check explicit closure signature annotation,
|
||||||
|
/// e.g., `|x: FxHashMap<_, &'static u32>| ...`.
|
||||||
|
#[instrument(skip(self, body), level = "debug")]
|
||||||
|
pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
|
||||||
|
let mir_def_id = body.source.def_id().expect_local();
|
||||||
|
if !self.tcx().is_closure(mir_def_id.to_def_id()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Some(user_provided_poly_sig) =
|
||||||
|
self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Instantiate the canonicalized variables from user-provided signature
|
||||||
|
// (e.g., the `_` in the code above) with fresh variables.
|
||||||
|
// Then replace the bound items in the fn sig with fresh variables,
|
||||||
|
// so that they represent the view from "inside" the closure.
|
||||||
|
let user_provided_sig = self
|
||||||
|
.instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig);
|
||||||
|
let user_provided_sig = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||||
|
body.span,
|
||||||
|
LateBoundRegionConversionTime::FnCall,
|
||||||
|
user_provided_sig,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip(
|
||||||
|
// In MIR, closure args begin with an implicit `self`. Skip it!
|
||||||
|
body.args_iter().skip(1).map(|local| &body.local_decls[local]),
|
||||||
|
) {
|
||||||
|
self.ascribe_user_type_skip_wf(
|
||||||
|
arg_decl.ty,
|
||||||
|
ty::UserType::Ty(user_ty),
|
||||||
|
arg_decl.source_info.span,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user explicitly annotated the output type, enforce it.
|
||||||
|
let output_decl = &body.local_decls[RETURN_PLACE];
|
||||||
|
self.ascribe_user_type_skip_wf(
|
||||||
|
output_decl.ty,
|
||||||
|
ty::UserType::Ty(user_provided_sig.output()),
|
||||||
|
output_decl.source_info.span,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, body, universal_regions), level = "debug")]
|
#[instrument(skip(self, body, universal_regions), level = "debug")]
|
||||||
pub(super) fn equate_inputs_and_outputs(
|
pub(super) fn equate_inputs_and_outputs(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -31,39 +77,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||||||
debug!(?normalized_output_ty);
|
debug!(?normalized_output_ty);
|
||||||
debug!(?normalized_input_tys);
|
debug!(?normalized_input_tys);
|
||||||
|
|
||||||
let mir_def_id = body.source.def_id().expect_local();
|
|
||||||
|
|
||||||
// If the user explicitly annotated the input types, extract
|
|
||||||
// those.
|
|
||||||
//
|
|
||||||
// e.g., `|x: FxHashMap<_, &'static u32>| ...`
|
|
||||||
let user_provided_sig = if !self.tcx().is_closure(mir_def_id.to_def_id()) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let typeck_results = self.tcx().typeck(mir_def_id);
|
|
||||||
|
|
||||||
typeck_results.user_provided_sigs.get(&mir_def_id).map(|user_provided_poly_sig| {
|
|
||||||
// Instantiate the canonicalized variables from
|
|
||||||
// user-provided signature (e.g., the `_` in the code
|
|
||||||
// above) with fresh variables.
|
|
||||||
let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
|
|
||||||
body.span,
|
|
||||||
&user_provided_poly_sig,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Replace the bound items in the fn sig with fresh
|
|
||||||
// variables, so that they represent the view from
|
|
||||||
// "inside" the closure.
|
|
||||||
self.infcx.replace_bound_vars_with_fresh_vars(
|
|
||||||
body.span,
|
|
||||||
LateBoundRegionConversionTime::FnCall,
|
|
||||||
poly_sig,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!(?normalized_input_tys, ?body.local_decls);
|
|
||||||
|
|
||||||
// Equate expected input tys with those in the MIR.
|
// Equate expected input tys with those in the MIR.
|
||||||
for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
|
for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
|
||||||
if argument_index + 1 >= body.local_decls.len() {
|
if argument_index + 1 >= body.local_decls.len() {
|
||||||
@ -86,28 +99,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(user_provided_sig) = user_provided_sig {
|
|
||||||
for (argument_index, &user_provided_input_ty) in
|
|
||||||
user_provided_sig.inputs().iter().enumerate()
|
|
||||||
{
|
|
||||||
// In MIR, closures begin an implicit `self`, so
|
|
||||||
// argument N is stored in local N+2.
|
|
||||||
let local = Local::new(argument_index + 2);
|
|
||||||
let mir_input_ty = body.local_decls[local].ty;
|
|
||||||
let mir_input_span = body.local_decls[local].source_info.span;
|
|
||||||
|
|
||||||
// If the user explicitly annotated the input types, enforce those.
|
|
||||||
let user_provided_input_ty =
|
|
||||||
self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
|
|
||||||
|
|
||||||
self.equate_normalized_input_or_output(
|
|
||||||
user_provided_input_ty,
|
|
||||||
mir_input_ty,
|
|
||||||
mir_input_span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
|
"equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
|
||||||
body.yield_ty(),
|
body.yield_ty(),
|
||||||
@ -153,29 +144,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||||||
terr
|
terr
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the user explicitly annotated the output types, enforce those.
|
|
||||||
// Note that this only happens for closures.
|
|
||||||
if let Some(user_provided_sig) = user_provided_sig {
|
|
||||||
let user_provided_output_ty = user_provided_sig.output();
|
|
||||||
let user_provided_output_ty =
|
|
||||||
self.normalize(user_provided_output_ty, Locations::All(output_span));
|
|
||||||
if let Err(err) = self.eq_types(
|
|
||||||
user_provided_output_ty,
|
|
||||||
mir_output_ty,
|
|
||||||
Locations::All(output_span),
|
|
||||||
ConstraintCategory::BoringNoLocation,
|
|
||||||
) {
|
|
||||||
span_mirbug!(
|
|
||||||
self,
|
|
||||||
Location::START,
|
|
||||||
"equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
|
|
||||||
mir_output_ty,
|
|
||||||
user_provided_output_ty,
|
|
||||||
err
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
@ -38,7 +38,6 @@ use rustc_middle::ty::{
|
|||||||
use rustc_span::def_id::CRATE_DEF_ID;
|
use rustc_span::def_id::CRATE_DEF_ID;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use rustc_trait_selection::traits::query::type_op;
|
|
||||||
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
|
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
|
||||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||||
@ -197,6 +196,8 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
|
checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
|
||||||
|
checker.check_signature_annotation(&body);
|
||||||
|
|
||||||
liveness::generate(
|
liveness::generate(
|
||||||
&mut checker,
|
&mut checker,
|
||||||
body,
|
body,
|
||||||
@ -391,23 +392,14 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||||||
check_err(self, promoted_body, ty, promoted_ty);
|
check_err(self, promoted_body, ty, promoted_ty);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Err(terr) = self.cx.fully_perform_op(
|
self.cx.ascribe_user_type(
|
||||||
locations,
|
constant.literal.ty(),
|
||||||
ConstraintCategory::Boring,
|
UserType::TypeOf(
|
||||||
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
|
|
||||||
constant.literal.ty(),
|
|
||||||
uv.def.did,
|
uv.def.did,
|
||||||
UserSubsts { substs: uv.substs, user_self_ty: None },
|
UserSubsts { substs: uv.substs, user_self_ty: None },
|
||||||
)),
|
),
|
||||||
) {
|
locations.span(&self.cx.body),
|
||||||
span_mirbug!(
|
);
|
||||||
self,
|
|
||||||
constant,
|
|
||||||
"bad constant type {:?} ({:?})",
|
|
||||||
constant,
|
|
||||||
terr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
|
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
|
||||||
let unnormalized_ty = tcx.type_of(static_def_id);
|
let unnormalized_ty = tcx.type_of(static_def_id);
|
||||||
@ -1041,58 +1033,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||||||
debug!(?self.user_type_annotations);
|
debug!(?self.user_type_annotations);
|
||||||
for user_annotation in 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 } = *user_annotation;
|
||||||
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
|
|
||||||
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
|
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
|
||||||
debug!(?annotation);
|
self.ascribe_user_type(inferred_ty, annotation, span);
|
||||||
match annotation {
|
|
||||||
UserType::Ty(mut ty) => {
|
|
||||||
ty = self.normalize(ty, Locations::All(span));
|
|
||||||
|
|
||||||
if let Err(terr) = self.eq_types(
|
|
||||||
ty,
|
|
||||||
inferred_ty,
|
|
||||||
Locations::All(span),
|
|
||||||
ConstraintCategory::BoringNoLocation,
|
|
||||||
) {
|
|
||||||
span_mirbug!(
|
|
||||||
self,
|
|
||||||
user_annotation,
|
|
||||||
"bad user type ({:?} = {:?}): {:?}",
|
|
||||||
ty,
|
|
||||||
inferred_ty,
|
|
||||||
terr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.prove_predicate(
|
|
||||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into())),
|
|
||||||
Locations::All(span),
|
|
||||||
ConstraintCategory::TypeAnnotation,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
UserType::TypeOf(def_id, user_substs) => {
|
|
||||||
if let Err(terr) = self.fully_perform_op(
|
|
||||||
Locations::All(span),
|
|
||||||
ConstraintCategory::BoringNoLocation,
|
|
||||||
self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
|
|
||||||
inferred_ty,
|
|
||||||
def_id,
|
|
||||||
user_substs,
|
|
||||||
)),
|
|
||||||
) {
|
|
||||||
span_mirbug!(
|
|
||||||
self,
|
|
||||||
user_annotation,
|
|
||||||
"bad user type AscribeUserType({:?}, {:?} {:?}, type_of={:?}): {:?}",
|
|
||||||
inferred_ty,
|
|
||||||
def_id,
|
|
||||||
user_substs,
|
|
||||||
self.tcx().type_of(def_id),
|
|
||||||
terr,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,22 +15,19 @@ use rustc_span::source_map::Span;
|
|||||||
|
|
||||||
pub mod type_op {
|
pub mod type_op {
|
||||||
use crate::ty::fold::TypeFoldable;
|
use crate::ty::fold::TypeFoldable;
|
||||||
use crate::ty::subst::UserSubsts;
|
use crate::ty::{Predicate, Ty, UserType};
|
||||||
use crate::ty::{Predicate, Ty};
|
|
||||||
use rustc_hir::def_id::DefId;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
||||||
#[derive(TypeFoldable, TypeVisitable)]
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
pub struct AscribeUserType<'tcx> {
|
pub struct AscribeUserType<'tcx> {
|
||||||
pub mir_ty: Ty<'tcx>,
|
pub mir_ty: Ty<'tcx>,
|
||||||
pub def_id: DefId,
|
pub user_ty: UserType<'tcx>,
|
||||||
pub user_substs: UserSubsts<'tcx>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> AscribeUserType<'tcx> {
|
impl<'tcx> AscribeUserType<'tcx> {
|
||||||
pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self {
|
pub fn new(mir_ty: Ty<'tcx>, user_ty: UserType<'tcx>) -> Self {
|
||||||
Self { mir_ty, def_id, user_substs }
|
Self { mir_ty, user_ty }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,7 +679,7 @@ impl<'tcx> CanonicalUserType<'tcx> {
|
|||||||
/// from constants that are named via paths, like `Foo::<A>::new` and
|
/// from constants that are named via paths, like `Foo::<A>::new` and
|
||||||
/// so forth.
|
/// so forth.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
||||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||||
pub enum UserType<'tcx> {
|
pub enum UserType<'tcx> {
|
||||||
Ty(Ty<'tcx>),
|
Ty(Ty<'tcx>),
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
|
|||||||
use rustc_infer::traits::ObligationCauseCode;
|
use rustc_infer::traits::ObligationCauseCode;
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_middle::ty::{ParamEnvAnd, Predicate, ToPredicate};
|
use rustc_middle::ty::{ParamEnvAnd, Predicate};
|
||||||
use rustc_middle::ty::{UserSelfTy, UserSubsts};
|
use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||||
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
|
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
|
||||||
@ -50,13 +50,46 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>(
|
|||||||
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
|
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
) -> Result<(), NoSolution> {
|
) -> Result<(), NoSolution> {
|
||||||
let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
|
let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
|
||||||
debug!(
|
debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
|
||||||
"type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
|
|
||||||
mir_ty, def_id, user_substs
|
|
||||||
);
|
|
||||||
let span = span.unwrap_or(DUMMY_SP);
|
let span = span.unwrap_or(DUMMY_SP);
|
||||||
|
match user_ty {
|
||||||
|
UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
|
||||||
|
UserType::TypeOf(def_id, user_substs) => {
|
||||||
|
relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(ocx, param_env, span))]
|
||||||
|
fn relate_mir_and_user_ty<'tcx>(
|
||||||
|
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
mir_ty: Ty<'tcx>,
|
||||||
|
user_ty: Ty<'tcx>,
|
||||||
|
) -> Result<(), NoSolution> {
|
||||||
|
let cause = ObligationCause::dummy_with_span(span);
|
||||||
|
let user_ty = ocx.normalize(&cause, param_env, user_ty);
|
||||||
|
ocx.eq(&cause, param_env, mir_ty, user_ty)?;
|
||||||
|
|
||||||
|
// FIXME(#104764): We should check well-formedness before normalization.
|
||||||
|
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
|
||||||
|
ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(ocx, param_env, span))]
|
||||||
|
fn relate_mir_and_user_substs<'tcx>(
|
||||||
|
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
mir_ty: Ty<'tcx>,
|
||||||
|
def_id: hir::def_id::DefId,
|
||||||
|
user_substs: UserSubsts<'tcx>,
|
||||||
|
) -> Result<(), NoSolution> {
|
||||||
let UserSubsts { user_self_ty, substs } = user_substs;
|
let UserSubsts { user_self_ty, substs } = user_substs;
|
||||||
let tcx = ocx.infcx.tcx;
|
let tcx = ocx.infcx.tcx;
|
||||||
let cause = ObligationCause::dummy_with_span(span);
|
let cause = ObligationCause::dummy_with_span(span);
|
||||||
@ -97,8 +130,7 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>(
|
|||||||
|
|
||||||
ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
|
ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
|
||||||
|
|
||||||
let predicate: Predicate<'tcx> =
|
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
|
||||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())).to_predicate(tcx);
|
|
||||||
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
|
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,8 +145,7 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>(
|
|||||||
// them? This would only be relevant if some input
|
// them? This would only be relevant if some input
|
||||||
// type were ill-formed but did not appear in `ty`,
|
// type were ill-formed but did not appear in `ty`,
|
||||||
// which...could happen with normalization...
|
// which...could happen with normalization...
|
||||||
let predicate: Predicate<'tcx> =
|
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()));
|
||||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(tcx);
|
|
||||||
ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
|
ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ LL | fn uninit<'a>() {
|
|||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | return;
|
LL | return;
|
||||||
LL | let x: &'static &'a ();
|
LL | let x: &'static &'a ();
|
||||||
| ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
error: lifetime may not live long enough
|
error: lifetime may not live long enough
|
||||||
--> $DIR/wf-unreachable.rs:11:12
|
--> $DIR/wf-unreachable.rs:11:12
|
||||||
@ -14,7 +14,7 @@ LL | fn var_type<'a>() {
|
|||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | return;
|
LL | return;
|
||||||
LL | let x: &'static &'a () = &&();
|
LL | let x: &'static &'a () = &&();
|
||||||
| ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
error: lifetime may not live long enough
|
error: lifetime may not live long enough
|
||||||
--> $DIR/wf-unreachable.rs:15:12
|
--> $DIR/wf-unreachable.rs:15:12
|
||||||
@ -22,7 +22,7 @@ error: lifetime may not live long enough
|
|||||||
LL | fn uninit_infer<'a>() {
|
LL | fn uninit_infer<'a>() {
|
||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | let x: &'static &'a _;
|
LL | let x: &'static &'a _;
|
||||||
| ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
error: lifetime may not live long enough
|
error: lifetime may not live long enough
|
||||||
--> $DIR/wf-unreachable.rs:21:12
|
--> $DIR/wf-unreachable.rs:21:12
|
||||||
@ -31,7 +31,7 @@ LL | fn infer<'a>() {
|
|||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | return;
|
LL | return;
|
||||||
LL | let x: &'static &'a _ = &&();
|
LL | let x: &'static &'a _ = &&();
|
||||||
| ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
error: lifetime may not live long enough
|
error: lifetime may not live long enough
|
||||||
--> $DIR/wf-unreachable.rs:26:12
|
--> $DIR/wf-unreachable.rs:26:12
|
||||||
@ -40,7 +40,7 @@ LL | fn uninit_no_var<'a>() {
|
|||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | return;
|
LL | return;
|
||||||
LL | let _: &'static &'a ();
|
LL | let _: &'static &'a ();
|
||||||
| ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
error: lifetime may not live long enough
|
error: lifetime may not live long enough
|
||||||
--> $DIR/wf-unreachable.rs:31:12
|
--> $DIR/wf-unreachable.rs:31:12
|
||||||
@ -49,7 +49,7 @@ LL | fn no_var<'a>() {
|
|||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | return;
|
LL | return;
|
||||||
LL | let _: &'static &'a () = &&();
|
LL | let _: &'static &'a () = &&();
|
||||||
| ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
error: lifetime may not live long enough
|
error: lifetime may not live long enough
|
||||||
--> $DIR/wf-unreachable.rs:36:12
|
--> $DIR/wf-unreachable.rs:36:12
|
||||||
@ -58,7 +58,7 @@ LL | fn infer_no_var<'a>() {
|
|||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | return;
|
LL | return;
|
||||||
LL | let _: &'static &'a _ = &&();
|
LL | let _: &'static &'a _ = &&();
|
||||||
| ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
error: lifetime may not live long enough
|
error: lifetime may not live long enough
|
||||||
--> $DIR/wf-unreachable.rs:49:12
|
--> $DIR/wf-unreachable.rs:49:12
|
||||||
@ -67,7 +67,7 @@ LL | fn required_substs<'a>() {
|
|||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | return;
|
LL | return;
|
||||||
LL | let _: C<'static, 'a, _> = C((), &(), &());
|
LL | let _: C<'static, 'a, _> = C((), &(), &());
|
||||||
| ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
error: aborting due to 8 previous errors
|
error: aborting due to 8 previous errors
|
||||||
|
|
||||||
|
15
src/test/ui/nll/user-annotations/closure-sig.rs
Normal file
15
src/test/ui/nll/user-annotations/closure-sig.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// This test fails if #104478 is fixed before #104477.
|
||||||
|
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
struct Printer<'a, 'b>(&'a (), &'b ());
|
||||||
|
|
||||||
|
impl Printer<'_, '_> {
|
||||||
|
fn test(self) {
|
||||||
|
let clo = |_: &'_ Self| {};
|
||||||
|
clo(&self);
|
||||||
|
clo(&self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
40
src/test/ui/nll/user-annotations/normalization-infer.rs
Normal file
40
src/test/ui/nll/user-annotations/normalization-infer.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Annnotations may contain projection types with inference variables as input.
|
||||||
|
// Make sure we don't get ambiguities when normalizing them.
|
||||||
|
|
||||||
|
// check-fail
|
||||||
|
|
||||||
|
// Single impl.
|
||||||
|
fn test1<A, B, C, D>(a: A, b: B, c: C) {
|
||||||
|
trait Tr { type Ty; }
|
||||||
|
impl<T: 'static> Tr for (T,) { type Ty = T; }
|
||||||
|
|
||||||
|
let _: <(_,) as Tr>::Ty = a; //~ ERROR type `A`
|
||||||
|
Some::<<(_,) as Tr>::Ty>(b); //~ ERROR type `B`
|
||||||
|
|| -> <(_,) as Tr>::Ty { c }; //~ ERROR type `C`
|
||||||
|
|d: <(_,) as Tr>::Ty| -> D { d }; //~ ERROR type `D`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Two impls. The selected impl depends on the actual type.
|
||||||
|
fn test2<A, B, C>(a: A, b: B, c: C) {
|
||||||
|
trait Tr { type Ty; }
|
||||||
|
impl<T: 'static> Tr for (u8, T) { type Ty = T; }
|
||||||
|
impl<T> Tr for (i8, T) { type Ty = T; }
|
||||||
|
type Alias<X, Y> = (<(X, Y) as Tr>::Ty, X);
|
||||||
|
|
||||||
|
fn temp() -> String { todo!() }
|
||||||
|
|
||||||
|
// `u8` impl, requires static.
|
||||||
|
let _: Alias<_, _> = (a, 0u8); //~ ERROR type `A`
|
||||||
|
Some::<Alias<_, _>>((b, 0u8)); //~ ERROR type `B`
|
||||||
|
|| -> Alias<_, _> { (c, 0u8) }; //~ ERROR type `C`
|
||||||
|
|
||||||
|
let _: Alias<_, _> = (&temp(), 0u8); //~ ERROR temporary value
|
||||||
|
Some::<Alias<_, _>>((&temp(), 0u8)); //~ ERROR temporary value
|
||||||
|
|
||||||
|
// `i8` impl, no region constraints.
|
||||||
|
let _: Alias<_, _> = (&temp(), 0i8);
|
||||||
|
Some::<Alias<_, _>>((&temp(), 0i8));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
101
src/test/ui/nll/user-annotations/normalization-infer.stderr
Normal file
101
src/test/ui/nll/user-annotations/normalization-infer.stderr
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
error[E0310]: the parameter type `A` may not live long enough
|
||||||
|
--> $DIR/normalization-infer.rs:11:12
|
||||||
|
|
|
||||||
|
LL | let _: <(_,) as Tr>::Ty = a;
|
||||||
|
| ^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound...
|
||||||
|
|
|
||||||
|
LL | fn test1<A: 'static, B, C, D>(a: A, b: B, c: C) {
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `B` may not live long enough
|
||||||
|
--> $DIR/normalization-infer.rs:12:5
|
||||||
|
|
|
||||||
|
LL | Some::<<(_,) as Tr>::Ty>(b);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound...
|
||||||
|
|
|
||||||
|
LL | fn test1<A, B: 'static, C, D>(a: A, b: B, c: C) {
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `C` may not live long enough
|
||||||
|
--> $DIR/normalization-infer.rs:13:11
|
||||||
|
|
|
||||||
|
LL | || -> <(_,) as Tr>::Ty { c };
|
||||||
|
| ^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound...
|
||||||
|
|
|
||||||
|
LL | fn test1<A, B, C: 'static, D>(a: A, b: B, c: C) {
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `D` may not live long enough
|
||||||
|
--> $DIR/normalization-infer.rs:14:6
|
||||||
|
|
|
||||||
|
LL | |d: <(_,) as Tr>::Ty| -> D { d };
|
||||||
|
| ^ ...so that the type `D` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound...
|
||||||
|
|
|
||||||
|
LL | fn test1<A, B, C, D: 'static>(a: A, b: B, c: C) {
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `A` may not live long enough
|
||||||
|
--> $DIR/normalization-infer.rs:28:12
|
||||||
|
|
|
||||||
|
LL | let _: Alias<_, _> = (a, 0u8);
|
||||||
|
| ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound...
|
||||||
|
|
|
||||||
|
LL | fn test2<A: 'static, B, C>(a: A, b: B, c: C) {
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `B` may not live long enough
|
||||||
|
--> $DIR/normalization-infer.rs:29:5
|
||||||
|
|
|
||||||
|
LL | Some::<Alias<_, _>>((b, 0u8));
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound...
|
||||||
|
|
|
||||||
|
LL | fn test2<A, B: 'static, C>(a: A, b: B, c: C) {
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `C` may not live long enough
|
||||||
|
--> $DIR/normalization-infer.rs:30:11
|
||||||
|
|
|
||||||
|
LL | || -> Alias<_, _> { (c, 0u8) };
|
||||||
|
| ^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound...
|
||||||
|
|
|
||||||
|
LL | fn test2<A, B, C: 'static>(a: A, b: B, c: C) {
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0716]: temporary value dropped while borrowed
|
||||||
|
--> $DIR/normalization-infer.rs:32:28
|
||||||
|
|
|
||||||
|
LL | let _: Alias<_, _> = (&temp(), 0u8);
|
||||||
|
| ----------- ^^^^^^ creates a temporary value which is freed while still in use
|
||||||
|
| |
|
||||||
|
| type annotation requires that borrow lasts for `'static`
|
||||||
|
...
|
||||||
|
LL | }
|
||||||
|
| - temporary value is freed at the end of this statement
|
||||||
|
|
||||||
|
error[E0716]: temporary value dropped while borrowed
|
||||||
|
--> $DIR/normalization-infer.rs:33:27
|
||||||
|
|
|
||||||
|
LL | Some::<Alias<_, _>>((&temp(), 0u8));
|
||||||
|
| --^^^^^^------ - temporary value is freed at the end of this statement
|
||||||
|
| | |
|
||||||
|
| | creates a temporary value which is freed while still in use
|
||||||
|
| this usage requires that borrow lasts for `'static`
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0310, E0716.
|
||||||
|
For more information about an error, try `rustc --explain E0310`.
|
@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() {
|
|||||||
| lifetime `'a` defined here
|
| lifetime `'a` defined here
|
||||||
...
|
...
|
||||||
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
|
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
||||||
|
|
|
|
||||||
= help: consider adding the following bound: `'b: 'a`
|
= help: consider adding the following bound: `'b: 'a`
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
|
|||||||
| |
|
| |
|
||||||
| lifetime `'a` defined here
|
| lifetime `'a` defined here
|
||||||
LL | let z: Option<&'b &'a usize> = None;
|
LL | let z: Option<&'b &'a usize> = None;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
|
| ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
|
||||||
|
|
|
|
||||||
= help: consider adding the following bound: `'a: 'b`
|
= help: consider adding the following bound: `'a: 'b`
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
|
|||||||
| lifetime `'a` defined here
|
| lifetime `'a` defined here
|
||||||
LL | let y: Paramd<'a> = Paramd { x: a };
|
LL | let y: Paramd<'a> = Paramd { x: a };
|
||||||
LL | let z: Option<&'b Paramd<'a>> = None;
|
LL | let z: Option<&'b Paramd<'a>> = None;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
|
| ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
|
||||||
|
|
|
|
||||||
= help: consider adding the following bound: `'a: 'b`
|
= help: consider adding the following bound: `'a: 'b`
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
|
|||||||
| |
|
| |
|
||||||
| lifetime `'a` defined here
|
| lifetime `'a` defined here
|
||||||
LL | let z: Option<&'a &'b usize> = None;
|
LL | let z: Option<&'a &'b usize> = None;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
|
| ^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
||||||
|
|
|
|
||||||
= help: consider adding the following bound: `'b: 'a`
|
= help: consider adding the following bound: `'b: 'a`
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() {
|
|||||||
| lifetime `'a` defined here
|
| lifetime `'a` defined here
|
||||||
...
|
...
|
||||||
LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
|
LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
||||||
|
|
|
|
||||||
= help: consider adding the following bound: `'b: 'a`
|
= help: consider adding the following bound: `'b: 'a`
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ LL | fn with_assoc_sub<'a,'b>() {
|
|||||||
| lifetime `'a` defined here
|
| lifetime `'a` defined here
|
||||||
...
|
...
|
||||||
LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
|
LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
||||||
|
|
|
|
||||||
= help: consider adding the following bound: `'b: 'a`
|
= help: consider adding the following bound: `'b: 'a`
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() {
|
|||||||
| lifetime `'a` defined here
|
| lifetime `'a` defined here
|
||||||
...
|
...
|
||||||
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
|
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
||||||
|
|
|
|
||||||
= help: consider adding the following bound: `'b: 'a`
|
= help: consider adding the following bound: `'b: 'a`
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() {
|
|||||||
| lifetime `'a` defined here
|
| lifetime `'a` defined here
|
||||||
...
|
...
|
||||||
LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
|
LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
||||||
|
|
|
|
||||||
= help: consider adding the following bound: `'b: 'a`
|
= help: consider adding the following bound: `'b: 'a`
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ LL | fn without_assoc<'a,'b>() {
|
|||||||
| lifetime `'a` defined here
|
| lifetime `'a` defined here
|
||||||
...
|
...
|
||||||
LL | let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
|
LL | let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
||||||
|
|
|
|
||||||
= help: consider adding the following bound: `'b: 'a`
|
= help: consider adding the following bound: `'b: 'a`
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user