diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 96326ef2d5a07..07289d68e2de3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -2,9 +2,13 @@ use rustc_errors::DiagnosticBuilder; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_infer::infer::region_constraints::Constraint; +use rustc_infer::infer::region_constraints::RegionConstraintData; +use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _}; use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt}; use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::RegionVid; +use rustc_middle::ty::UniverseIndex; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op; @@ -78,6 +82,15 @@ crate trait ToUniverseInfo<'tcx> { fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>; } +impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { + fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType { + base_universe: Some(base_universe), + ..self + }))) + } +} + impl<'tcx> ToUniverseInfo<'tcx> for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>> { @@ -118,6 +131,12 @@ impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::Custo } } +impl<'tcx> ToUniverseInfo<'tcx> for ! { + fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + self + } +} + #[allow(unused_lifetimes)] trait TypeOpInfo<'tcx> { /// Returns an error to be reported if rerunning the type op fails to @@ -128,7 +147,7 @@ trait TypeOpInfo<'tcx> { fn nice_error( &self, - tcx: TyCtxt<'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, @@ -175,7 +194,7 @@ trait TypeOpInfo<'tcx> { debug!(?placeholder_region); let span = cause.span; - let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region); + let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region); if let Some(nice_error) = nice_error { nice_error.buffer(&mut mbcx.errors_buffer); @@ -204,16 +223,16 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { fn nice_error( &self, - tcx: TyCtxt<'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical( + mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( cause.span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); + let mut fulfill_cx = >::new(infcx.tcx); type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); try_extract_error_from_fulfill_cx( fulfill_cx, @@ -247,16 +266,16 @@ where fn nice_error( &self, - tcx: TyCtxt<'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical( + mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( cause.span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); + let mut fulfill_cx = >::new(infcx.tcx); let mut selcx = SelectionContext::new(infcx); @@ -304,16 +323,16 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { fn nice_error( &self, - tcx: TyCtxt<'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical( + mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( cause.span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); + let mut fulfill_cx = >::new(infcx.tcx); type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)) .ok()?; try_extract_error_from_fulfill_cx( @@ -327,6 +346,39 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { } } +impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, + // and is only the fallback when the nice error fails. Consider improving this some more. + tcx.sess.struct_span_err(span, "higher-ranked lifetime error for opaque type!") + } + + fn base_universe(&self) -> ty::UniverseIndex { + self.base_universe.unwrap() + } + + fn nice_error( + &self, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, + _cause: ObligationCause<'tcx>, + placeholder_region: ty::Region<'tcx>, + error_region: Option>, + ) -> Option> { + try_extract_error_from_region_constraints( + mbcx.infcx, + placeholder_region, + error_region, + self.region_constraints.as_ref().unwrap(), + // We're using the original `InferCtxt` that we + // started MIR borrowchecking with, so the region + // constraints have already been taken. Use the data from + // our `mbcx` instead. + |vid| mbcx.regioncx.var_infos[vid].origin, + |vid| mbcx.regioncx.var_infos[vid].universe, + ) + } +} + #[instrument(skip(fulfill_cx, infcx), level = "debug")] fn try_extract_error_from_fulfill_cx<'tcx>( mut fulfill_cx: Box + 'tcx>, @@ -334,15 +386,30 @@ fn try_extract_error_from_fulfill_cx<'tcx>( placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - let tcx = infcx.tcx; - // We generally shouldn't have errors here because the query was // already run, but there's no point using `delay_span_bug` // when we're going to emit an error here anyway. let _errors = fulfill_cx.select_all_or_error(infcx); + let region_constraints = infcx.with_region_constraints(|r| r.clone()); + try_extract_error_from_region_constraints( + infcx, + placeholder_region, + error_region, + ®ion_constraints, + |vid| infcx.region_var_origin(vid), + |vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))), + ) +} - let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| { - debug!("{:#?}", region_constraints); +fn try_extract_error_from_region_constraints<'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + placeholder_region: ty::Region<'tcx>, + error_region: Option>, + region_constraints: &RegionConstraintData<'tcx>, + mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin, + mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex, +) -> Option> { + let (sub_region, cause) = region_constraints.constraints.iter().find_map(|(constraint, cause)| { match *constraint { Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => { @@ -350,12 +417,11 @@ fn try_extract_error_from_fulfill_cx<'tcx>( } // FIXME: Should this check the universe of the var? Constraint::VarSubReg(vid, sup) if sup == placeholder_region => { - Some((tcx.mk_region(ty::ReVar(vid)), cause.clone())) + Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone())) } _ => None, } - }) - })?; + })?; debug!(?sub_region, "cause = {:#?}", cause); let nice_error = match (error_region, sub_region) { @@ -363,7 +429,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( infcx, RegionResolutionError::SubSupConflict( vid, - infcx.region_var_origin(vid), + region_var_origin(vid), cause.clone(), error_region, cause.clone(), @@ -380,8 +446,8 @@ fn try_extract_error_from_fulfill_cx<'tcx>( infcx, RegionResolutionError::UpperBoundUniverseConflict( vid, - infcx.region_var_origin(vid), - infcx.universe_of_region(sub_region), + region_var_origin(vid), + universe_of_region(vid), cause.clone(), placeholder_region, ), diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index c318386f33b13..d698131df18dc 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -5,6 +5,7 @@ #![feature(crate_visibility_modifier)] #![feature(let_else)] #![feature(min_specialization)] +#![feature(never_type)] #![feature(stmt_expr_attributes)] #![feature(trusted_step)] #![feature(try_blocks)] diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index d9120ff245735..1dc9240620b13 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -44,6 +44,7 @@ mod reverse_sccs; pub mod values; pub struct RegionInferenceContext<'tcx> { + pub var_infos: VarInfos, /// Contains the definition for every region variable. Region /// variables are identified by their index (`RegionVid`). The /// definition contains information about where the region came @@ -266,7 +267,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> Self { // Create a RegionDefinition for each inference variable. let definitions: IndexVec<_, _> = var_infos - .into_iter() + .iter() .map(|info| RegionDefinition::new(info.universe, info.origin)) .collect(); @@ -291,6 +292,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r))); let mut result = Self { + var_infos, definitions, liveness_constraints, constraints, diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 0fa72ed8241bc..3856b7f4a4b82 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -33,12 +33,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ) -> Fallible where Op: type_op::TypeOp<'tcx, Output = R>, - Canonical<'tcx, Op>: ToUniverseInfo<'tcx>, + Op::ErrorInfo: ToUniverseInfo<'tcx>, { let old_universe = self.infcx.universe(); - let TypeOpOutput { output, constraints, canonicalized_query } = - op.fully_perform(self.infcx)?; + let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?; if let Some(data) = &constraints { self.push_region_constraints(locations, category, data); @@ -47,8 +46,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let universe = self.infcx.universe(); if old_universe != universe { - let universe_info = match canonicalized_query { - Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe), + let universe_info = match error_info { + Some(error_info) => error_info.to_universe_info(old_universe), None => UniverseInfo::other(), }; for u in old_universe..universe { diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index fec6bdf314b1d..48d8ae8947ff7 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -268,7 +268,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { TypeOpOutput { output: self.infcx.tcx.ty_error(), constraints: None, - canonicalized_query: None, + error_info: None, } }); // Note: we need this in examples like diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 4647610b0033d..97021aa228420 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -17,6 +17,7 @@ use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; +use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin, @@ -39,9 +40,11 @@ use rustc_target::abi::VariantIdx; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; 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::CustomTypeOp; +use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use rustc_trait_selection::traits::query::Fallible; -use rustc_trait_selection::traits::{self, ObligationCause}; +use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; use rustc_const_eval::transform::{ check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression, @@ -2637,3 +2640,32 @@ impl NormalizeLocation for Location { Locations::Single(self) } } + +/// Runs `infcx.instantiate_opaque_types`. Unlike other `TypeOp`s, +/// this is not canonicalized - it directly affects the main `InferCtxt` +/// that we use during MIR borrowchecking. +#[derive(Debug)] +pub(super) struct InstantiateOpaqueType<'tcx> { + pub base_universe: Option, + pub region_constraints: Option>, + pub obligation: PredicateObligation<'tcx>, +} + +impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> { + type Output = (); + /// We use this type itself to store the information used + /// when reporting errors. Since this is not a query, we don't + /// re-run anything during error reporting - we just use the information + /// we saved to help extract an error from the already-existing region + /// constraints in our `InferCtxt` + type ErrorInfo = InstantiateOpaqueType<'tcx>; + + fn fully_perform(mut self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible> { + let (mut output, region_constraints) = scrape_region_constraints(infcx, || { + Ok(InferOk { value: (), obligations: vec![self.obligation.clone()] }) + })?; + self.region_constraints = Some(region_constraints); + output.error_info = Some(self); + Ok(output) + } +} diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index aba1dd2bc548c..1d6ad697443aa 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,5 +1,5 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; -use rustc_infer::infer::{InferOk, NllRegionVariableOrigin}; +use rustc_infer::infer::NllRegionVariableOrigin; use rustc_infer::traits::ObligationCause; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; @@ -9,7 +9,7 @@ use rustc_trait_selection::traits::query::Fallible; use crate::constraints::OutlivesConstraint; use crate::diagnostics::UniverseInfo; -use crate::type_check::{CustomTypeOp, Locations, TypeChecker}; +use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker}; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: @@ -146,21 +146,18 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> .fully_perform_op( self.locations, self.category, - CustomTypeOp::new( - |infcx| { - Ok(InferOk { - value: (), - obligations: vec![infcx.opaque_ty_obligation( - a, - b, - a_is_expected, - param_env, - cause, - )], - }) - }, - || "register_opaque_type".to_string(), - ), + InstantiateOpaqueType { + obligation: self.type_checker.infcx.opaque_ty_obligation( + a, + b, + a_is_expected, + param_env, + cause, + ), + // These fields are filled in during exectuion of the operation + base_universe: None, + region_constraints: None, + }, ) .unwrap(); } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index ae79e14db181c..f4df86e2ac7d3 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -22,6 +22,7 @@ #![feature(control_flow_enum)] #![feature(min_specialization)] #![feature(label_break_value)] +#![feature(backtrace)] #![recursion_limit = "512"] // For rustdoc #![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 3aa5ee366f78f..605c9ace5ed06 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -4,6 +4,7 @@ use crate::traits::engine::TraitEngineExt as _; use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::Fallible; use crate::traits::TraitEngine; +use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::DUMMY_SP; @@ -31,6 +32,9 @@ where G: Fn() -> String, { type Output = R; + /// We can't do any custom error reporting for `CustomTypeOp`, so + /// we can use `!` to enforce that the implementation never provides it. + type ErrorInfo = !; /// Processes the operation and all resulting obligations, /// returning the final result along with any region constraints @@ -40,7 +44,7 @@ where info!("fully_perform({:?})", self); } - scrape_region_constraints(infcx, || (self.closure)(infcx)) + Ok(scrape_region_constraints(infcx, || (self.closure)(infcx))?.0) } } @@ -55,10 +59,10 @@ where /// Executes `op` and then scrapes out all the "old style" region /// constraints that result, creating query-region-constraints. -fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( +pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx: &InferCtxt<'_, 'tcx>, op: impl FnOnce() -> Fallible>, -) -> Fallible> { +) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { let mut fulfill_cx = >::new(infcx.tcx); // During NLL, we expect that nobody will register region @@ -97,12 +101,18 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( ); if region_constraints.is_empty() { - Ok(TypeOpOutput { output: value, constraints: None, canonicalized_query: None }) + Ok(( + TypeOpOutput { output: value, constraints: None, error_info: None }, + region_constraint_data, + )) } else { - Ok(TypeOpOutput { - output: value, - constraints: Some(Rc::new(region_constraints)), - canonicalized_query: None, - }) + Ok(( + TypeOpOutput { + output: value, + constraints: Some(Rc::new(region_constraints)), + error_info: None, + }, + region_constraint_data, + )) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index d662f61e2cf4d..1e72dd693396a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -28,6 +28,7 @@ pub use rustc_middle::traits::query::type_op::*; /// cannot be completed). pub trait TypeOp<'tcx>: Sized + fmt::Debug { type Output; + type ErrorInfo; /// Processes the operation and all resulting obligations, /// returning the final result along with any region constraints @@ -41,9 +42,8 @@ pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> { pub output: Op::Output, /// Any region constraints from performing the type op. pub constraints: Option>>, - /// The canonicalized form of the query. - /// This for error reporting to be able to rerun the query. - pub canonicalized_query: Option>, + /// Used for error reporting to be able to rerun the query + pub error_info: Option, } /// "Query type ops" are type ops that are implemented using a @@ -119,10 +119,11 @@ where Q: QueryTypeOp<'tcx>, { type Output = Q::QueryResponse; + type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>; fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible> { let mut region_constraints = QueryRegionConstraints::default(); - let (output, canonicalized_query, mut obligations, _) = + let (output, error_info, mut obligations, _) = Q::fully_perform_into(self, infcx, &mut region_constraints)?; // Typically, instantiating NLL query results does not @@ -160,6 +161,6 @@ where let region_constraints = if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) }; - Ok(TypeOpOutput { output, constraints: region_constraints, canonicalized_query }) + Ok(TypeOpOutput { output, constraints: region_constraints, error_info }) } } diff --git a/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr b/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr index 86323add77905..9cf8ff76c87f8 100644 --- a/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr +++ b/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr @@ -1,14 +1,20 @@ -error: higher-ranked subtype error +error: implementation of `Hrtb` is not general enough --> $DIR/issue-88236-2.rs:17:5 | LL | &() - | ^^^ + | ^^^ implementation of `Hrtb` is not general enough + | + = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... + = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` -error: higher-ranked subtype error +error: implementation of `Hrtb` is not general enough --> $DIR/issue-88236-2.rs:17:5 | LL | &() - | ^^^ + | ^^^ implementation of `Hrtb` is not general enough + | + = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... + = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` error: lifetime may not live long enough --> $DIR/issue-88236-2.rs:20:5 @@ -23,17 +29,23 @@ help: to allow this `impl Trait` to capture borrowed data with lifetime `'b`, ad LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b { | ++++ -error: higher-ranked subtype error +error: implementation of `Hrtb` is not general enough --> $DIR/issue-88236-2.rs:20:5 | LL | x - | ^ + | ^ implementation of `Hrtb` is not general enough + | + = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... + = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` -error: higher-ranked subtype error +error: implementation of `Hrtb` is not general enough --> $DIR/issue-88236-2.rs:20:5 | LL | x - | ^ + | ^ implementation of `Hrtb` is not general enough + | + = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... + = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` error: aborting due to 5 previous errors diff --git a/src/test/ui/nll/relate_tys/opaque-hrtb.rs b/src/test/ui/nll/relate_tys/opaque-hrtb.rs new file mode 100644 index 0000000000000..0fbe6a63c0b68 --- /dev/null +++ b/src/test/ui/nll/relate_tys/opaque-hrtb.rs @@ -0,0 +1,16 @@ +#![feature(nll)] + +trait MyTrait {} + +struct Foo; +impl MyTrait for Foo {} + +fn bar() -> impl MyTrait { + Foo +} + +fn foo() -> impl for<'a> MyTrait<&'a str> { + bar() //~ ERROR implementation of `MyTrait` is not general enough +} + +fn main() {} diff --git a/src/test/ui/nll/relate_tys/opaque-hrtb.stderr b/src/test/ui/nll/relate_tys/opaque-hrtb.stderr new file mode 100644 index 0000000000000..4c8b66f21abe0 --- /dev/null +++ b/src/test/ui/nll/relate_tys/opaque-hrtb.stderr @@ -0,0 +1,11 @@ +error: implementation of `MyTrait` is not general enough + --> $DIR/opaque-hrtb.rs:13:5 + | +LL | bar() + | ^^^^^ implementation of `MyTrait` is not general enough + | + = note: `impl MyTrait<&'2 str>` must implement `MyTrait<&'1 str>`, for any lifetime `'1`... + = note: ...but it actually implements `MyTrait<&'2 str>`, for some specific lifetime `'2` + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr index 1538274d45cb2..91daa65d6563a 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr @@ -1,14 +1,26 @@ -error: higher-ranked subtype error +error[E0308]: mismatched types + --> $DIR/issue-57611-trait-alias.rs:20:9 + | +LL | |x| x + | ^^^^^ one type is more general than the other + | + = note: expected type `for<'r> Fn<(&'r X,)>` + found type `Fn<(&X,)>` +note: this closure does not fulfill the lifetime requirements --> $DIR/issue-57611-trait-alias.rs:20:9 | LL | |x| x | ^^^^^ -error: higher-ranked subtype error +error: implementation of `FnOnce` is not general enough --> $DIR/issue-57611-trait-alias.rs:20:9 | LL | |x| x - | ^^^^^ + | ^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`.