bors 2022-02-11 17:39:34 +00:00
commit 6499c5e7fc
370 changed files with 2487 additions and 3626 deletions

View File

@ -2,13 +2,9 @@ use rustc_errors::DiagnosticBuilder;
use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_infer::infer::region_constraints::Constraint; 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::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt}; use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
use rustc_middle::ty::error::TypeError; 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_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op; use rustc_trait_selection::traits::query::type_op;
@ -82,15 +78,6 @@ crate trait ToUniverseInfo<'tcx> {
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'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> impl<'tcx> ToUniverseInfo<'tcx>
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>> for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
{ {
@ -131,12 +118,6 @@ 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)] #[allow(unused_lifetimes)]
trait TypeOpInfo<'tcx> { trait TypeOpInfo<'tcx> {
/// Returns an error to be reported if rerunning the type op fails to /// Returns an error to be reported if rerunning the type op fails to
@ -147,7 +128,7 @@ trait TypeOpInfo<'tcx> {
fn nice_error( fn nice_error(
&self, &self,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, tcx: TyCtxt<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
@ -194,7 +175,7 @@ trait TypeOpInfo<'tcx> {
debug!(?placeholder_region); debug!(?placeholder_region);
let span = cause.span; let span = cause.span;
let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region); let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
if let Some(nice_error) = nice_error { if let Some(nice_error) = nice_error {
nice_error.buffer(&mut mbcx.errors_buffer); nice_error.buffer(&mut mbcx.errors_buffer);
@ -223,16 +204,16 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
fn nice_error( fn nice_error(
&self, &self,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, tcx: TyCtxt<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>> { ) -> Option<DiagnosticBuilder<'tcx>> {
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( tcx.infer_ctxt().enter_with_canonical(
cause.span, cause.span,
&self.canonical_query, &self.canonical_query,
|ref infcx, key, _| { |ref infcx, key, _| {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
try_extract_error_from_fulfill_cx( try_extract_error_from_fulfill_cx(
fulfill_cx, fulfill_cx,
@ -266,16 +247,16 @@ where
fn nice_error( fn nice_error(
&self, &self,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, tcx: TyCtxt<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>> { ) -> Option<DiagnosticBuilder<'tcx>> {
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( tcx.infer_ctxt().enter_with_canonical(
cause.span, cause.span,
&self.canonical_query, &self.canonical_query,
|ref infcx, key, _| { |ref infcx, key, _| {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
let mut selcx = SelectionContext::new(infcx); let mut selcx = SelectionContext::new(infcx);
@ -323,16 +304,16 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
fn nice_error( fn nice_error(
&self, &self,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, tcx: TyCtxt<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>> { ) -> Option<DiagnosticBuilder<'tcx>> {
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( tcx.infer_ctxt().enter_with_canonical(
cause.span, cause.span,
&self.canonical_query, &self.canonical_query,
|ref infcx, key, _| { |ref infcx, key, _| {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)) type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
.ok()?; .ok()?;
try_extract_error_from_fulfill_cx( try_extract_error_from_fulfill_cx(
@ -346,39 +327,6 @@ 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<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>> {
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")] #[instrument(skip(fulfill_cx, infcx), level = "debug")]
fn try_extract_error_from_fulfill_cx<'tcx>( fn try_extract_error_from_fulfill_cx<'tcx>(
mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>, mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
@ -386,30 +334,15 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
placeholder_region: ty::Region<'tcx>, placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>, error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>> { ) -> Option<DiagnosticBuilder<'tcx>> {
let tcx = infcx.tcx;
// We generally shouldn't have errors here because the query was // We generally shouldn't have errors here because the query was
// already run, but there's no point using `delay_span_bug` // already run, but there's no point using `delay_span_bug`
// when we're going to emit an error here anyway. // when we're going to emit an error here anyway.
let _errors = fulfill_cx.select_all_or_error(infcx); 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,
&region_constraints,
|vid| infcx.region_var_origin(vid),
|vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))),
)
}
fn try_extract_error_from_region_constraints<'tcx>( let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
infcx: &InferCtxt<'_, 'tcx>, debug!("{:#?}", region_constraints);
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
region_constraints: &RegionConstraintData<'tcx>,
mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
) -> Option<DiagnosticBuilder<'tcx>> {
let (sub_region, cause) =
region_constraints.constraints.iter().find_map(|(constraint, cause)| { region_constraints.constraints.iter().find_map(|(constraint, cause)| {
match *constraint { match *constraint {
Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => { Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
@ -417,11 +350,12 @@ fn try_extract_error_from_region_constraints<'tcx>(
} }
// FIXME: Should this check the universe of the var? // FIXME: Should this check the universe of the var?
Constraint::VarSubReg(vid, sup) if sup == placeholder_region => { Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone())) Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
} }
_ => None, _ => None,
} }
})?; })
})?;
debug!(?sub_region, "cause = {:#?}", cause); debug!(?sub_region, "cause = {:#?}", cause);
let nice_error = match (error_region, sub_region) { let nice_error = match (error_region, sub_region) {
@ -429,7 +363,7 @@ fn try_extract_error_from_region_constraints<'tcx>(
infcx, infcx,
RegionResolutionError::SubSupConflict( RegionResolutionError::SubSupConflict(
vid, vid,
region_var_origin(vid), infcx.region_var_origin(vid),
cause.clone(), cause.clone(),
error_region, error_region,
cause.clone(), cause.clone(),
@ -446,8 +380,8 @@ fn try_extract_error_from_region_constraints<'tcx>(
infcx, infcx,
RegionResolutionError::UpperBoundUniverseConflict( RegionResolutionError::UpperBoundUniverseConflict(
vid, vid,
region_var_origin(vid), infcx.region_var_origin(vid),
universe_of_region(vid), infcx.universe_of_region(sub_region),
cause.clone(), cause.clone(),
placeholder_region, placeholder_region,
), ),

View File

@ -5,7 +5,6 @@
#![feature(crate_visibility_modifier)] #![feature(crate_visibility_modifier)]
#![feature(let_else)] #![feature(let_else)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(never_type)]
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
#![feature(trusted_step)] #![feature(trusted_step)]
#![feature(try_blocks)] #![feature(try_blocks)]
@ -125,9 +124,8 @@ fn mir_borrowck<'tcx>(
) -> &'tcx BorrowCheckResult<'tcx> { ) -> &'tcx BorrowCheckResult<'tcx> {
let (input_body, promoted) = tcx.mir_promoted(def); let (input_body, promoted) = tcx.mir_promoted(def);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id())); debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| { let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
let input_body: &Body<'_> = &input_body.borrow(); let input_body: &Body<'_> = &input_body.borrow();
let promoted: &IndexVec<_, _> = &promoted.borrow(); let promoted: &IndexVec<_, _> = &promoted.borrow();
do_mir_borrowck(&infcx, input_body, promoted, false).0 do_mir_borrowck(&infcx, input_body, promoted, false).0
@ -142,7 +140,7 @@ fn mir_borrowck<'tcx>(
/// If `return_body_with_facts` is true, then return the body with non-erased /// If `return_body_with_facts` is true, then return the body with non-erased
/// region ids on which the borrow checking was performed together with Polonius /// region ids on which the borrow checking was performed together with Polonius
/// facts. /// facts.
#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")] #[instrument(skip(infcx, input_body, input_promoted), level = "debug")]
fn do_mir_borrowck<'a, 'tcx>( fn do_mir_borrowck<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>, infcx: &InferCtxt<'a, 'tcx>,
input_body: &Body<'tcx>, input_body: &Body<'tcx>,

View File

@ -44,7 +44,6 @@ mod reverse_sccs;
pub mod values; pub mod values;
pub struct RegionInferenceContext<'tcx> { pub struct RegionInferenceContext<'tcx> {
pub var_infos: VarInfos,
/// Contains the definition for every region variable. Region /// Contains the definition for every region variable. Region
/// variables are identified by their index (`RegionVid`). The /// variables are identified by their index (`RegionVid`). The
/// definition contains information about where the region came /// definition contains information about where the region came
@ -267,7 +266,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
) -> Self { ) -> Self {
// Create a RegionDefinition for each inference variable. // Create a RegionDefinition for each inference variable.
let definitions: IndexVec<_, _> = var_infos let definitions: IndexVec<_, _> = var_infos
.iter() .into_iter()
.map(|info| RegionDefinition::new(info.universe, info.origin)) .map(|info| RegionDefinition::new(info.universe, info.origin))
.collect(); .collect();
@ -292,7 +291,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r))); Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
let mut result = Self { let mut result = Self {
var_infos,
definitions, definitions,
liveness_constraints, liveness_constraints,
constraints, constraints,

View File

@ -1,6 +1,7 @@
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::vec_map::VecMap; use rustc_data_structures::vec_map::VecMap;
use rustc_hir::OpaqueTyOrigin; use rustc_hir::OpaqueTyOrigin;
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
@ -53,44 +54,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn infer_opaque_types( pub(crate) fn infer_opaque_types(
&self, &self,
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (Ty<'tcx>, Span, OpaqueTyOrigin)>, opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
span: Span, span: Span,
) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> { ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
opaque_ty_decls opaque_ty_decls
.into_iter() .into_iter()
.map(|(opaque_type_key, (concrete_type, decl_span, origin))| { .filter_map(|(opaque_type_key, decl)| {
let substs = opaque_type_key.substs; let substs = opaque_type_key.substs;
// FIXME: why are the spans in decl_span often DUMMY_SP? let concrete_type = decl.concrete_ty;
let span = decl_span.substitute_dummy(span);
debug!(?concrete_type, ?substs); debug!(?concrete_type, ?substs);
let mut subst_regions = vec![self.universal_regions.fr_static]; let mut subst_regions = vec![self.universal_regions.fr_static];
let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| { let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
if let ty::RePlaceholder(..) = region { let vid = self.universal_regions.to_region_vid(region);
// Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs. subst_regions.push(vid);
return region; self.definitions[vid].external_name.unwrap_or_else(|| {
} infcx
let vid = self.to_region_vid(region); .tcx
trace!(?vid); .sess
let scc = self.constraint_sccs.scc(vid); .delay_span_bug(span, "opaque type with non-universal region substs");
trace!(?scc); infcx.tcx.lifetimes.re_static
match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| { })
self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
}) {
Some(region) => {
let vid = self.universal_regions.to_region_vid(region);
subst_regions.push(vid);
region
}
None => {
subst_regions.push(vid);
infcx.tcx.sess.delay_span_bug(
span,
"opaque type with non-universal region substs",
);
infcx.tcx.lifetimes.re_static
}
}
}); });
subst_regions.sort(); subst_regions.sort();
@ -116,14 +100,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
span, span,
); );
( check_opaque_type_parameter_valid(
infcx.tcx,
opaque_type_key, opaque_type_key,
if check_opaque_type_parameter_valid(infcx.tcx, opaque_type_key, origin, span) { OpaqueTypeDecl { concrete_ty: remapped_type, ..decl },
remapped_type
} else {
infcx.tcx.ty_error()
},
) )
.then_some((opaque_type_key, remapped_type))
}) })
.collect() .collect()
} }
@ -167,10 +149,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn check_opaque_type_parameter_valid( fn check_opaque_type_parameter_valid(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
opaque_type_key: OpaqueTypeKey<'_>, opaque_type_key: OpaqueTypeKey<'_>,
origin: OpaqueTyOrigin, decl: OpaqueTypeDecl<'_>,
span: Span,
) -> bool { ) -> bool {
match origin { match decl.origin {
// No need to check return position impl trait (RPIT) // No need to check return position impl trait (RPIT)
// because for type and const parameters they are correct // because for type and const parameters they are correct
// by construction: we convert // by construction: we convert
@ -196,6 +177,7 @@ fn check_opaque_type_parameter_valid(
// Check these // Check these
OpaqueTyOrigin::TyAlias => {} OpaqueTyOrigin::TyAlias => {}
} }
let span = decl.definition_span;
let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
for (i, arg) in opaque_type_key.substs.iter().enumerate() { for (i, arg) in opaque_type_key.substs.iter().enumerate() {

View File

@ -33,11 +33,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
) -> Fallible<R> ) -> Fallible<R>
where where
Op: type_op::TypeOp<'tcx, Output = R>, Op: type_op::TypeOp<'tcx, Output = R>,
Op::ErrorInfo: ToUniverseInfo<'tcx>, Canonical<'tcx, Op>: ToUniverseInfo<'tcx>,
{ {
let old_universe = self.infcx.universe(); let old_universe = self.infcx.universe();
let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?; let TypeOpOutput { output, constraints, canonicalized_query } =
op.fully_perform(self.infcx)?;
if let Some(data) = &constraints { if let Some(data) = &constraints {
self.push_region_constraints(locations, category, data); self.push_region_constraints(locations, category, data);
@ -46,8 +47,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let universe = self.infcx.universe(); let universe = self.infcx.universe();
if old_universe != universe { if old_universe != universe {
let universe_info = match error_info { let universe_info = match canonicalized_query {
Some(error_info) => error_info.to_universe_info(old_universe), Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe),
None => UniverseInfo::other(), None => UniverseInfo::other(),
}; };
for u in old_universe..universe { for u in old_universe..universe {

View File

@ -268,7 +268,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
TypeOpOutput { TypeOpOutput {
output: self.infcx.tcx.ty_error(), output: self.infcx.tcx.ty_error(),
constraints: None, constraints: None,
error_info: None, canonicalized_query: None,
} }
}); });
// Note: we need this in examples like // Note: we need this in examples like

View File

@ -147,9 +147,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// Return types are a bit more complex. They may contain opaque `impl Trait` types. // Return types are a bit more complex. They may contain opaque `impl Trait` types.
let mir_output_ty = body.local_decls[RETURN_PLACE].ty; let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
let output_span = body.local_decls[RETURN_PLACE].source_info.span; let output_span = body.local_decls[RETURN_PLACE].source_info.span;
if let Err(terr) = self.eq_types( if let Err(terr) = self.eq_opaque_type_and_type(
normalized_output_ty,
mir_output_ty, mir_output_ty,
normalized_output_ty,
Locations::All(output_span), Locations::All(output_span),
ConstraintCategory::BoringNoLocation, ConstraintCategory::BoringNoLocation,
) { ) {
@ -169,9 +169,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let user_provided_output_ty = user_provided_sig.output(); let user_provided_output_ty = user_provided_sig.output();
let user_provided_output_ty = let user_provided_output_ty =
self.normalize(user_provided_output_ty, Locations::All(output_span)); self.normalize(user_provided_output_ty, Locations::All(output_span));
if let Err(err) = self.eq_types( if let Err(err) = self.eq_opaque_type_and_type(
user_provided_output_ty,
mir_output_ty, mir_output_ty,
user_provided_output_ty,
Locations::All(output_span), Locations::All(output_span),
ConstraintCategory::BoringNoLocation, ConstraintCategory::BoringNoLocation,
) { ) {

View File

@ -5,7 +5,6 @@ use std::{fmt, iter, mem};
use either::Either; use either::Either;
use hir::OpaqueTyOrigin;
use rustc_data_structures::frozen::Frozen; use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::vec_map::VecMap; use rustc_data_structures::vec_map::VecMap;
@ -16,8 +15,8 @@ use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_index::vec::{Idx, IndexVec}; use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
use rustc_infer::infer::outlives::env::RegionBoundPairs; 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::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{ use rustc_infer::infer::{
InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin, InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin,
@ -40,11 +39,9 @@ use rustc_target::abi::VariantIdx;
use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::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;
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::Fallible; use rustc_trait_selection::traits::query::Fallible;
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
use rustc_const_eval::transform::{ use rustc_const_eval::transform::{
check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression, check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
@ -78,7 +75,7 @@ macro_rules! span_mirbug {
$context.last_span, $context.last_span,
&format!( &format!(
"broken MIR in {:?} ({:?}): {}", "broken MIR in {:?} ({:?}): {}",
$context.body().source.def_id(), $context.body.source.def_id(),
$elem, $elem,
format_args!($($message)*), format_args!($($message)*),
), ),
@ -193,44 +190,59 @@ pub(crate) fn type_check<'mir, 'tcx>(
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
translate_outlives_facts(&mut cx); translate_outlives_facts(&mut cx);
let opaque_type_values = let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
opaque_type_values opaque_type_values
.into_iter() .into_iter()
.map(|(opaque_type_key, decl)| { .filter_map(|(opaque_type_key, mut decl)| {
cx.fully_perform_op( decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
Locations::All(body.span),
ConstraintCategory::OpaqueType,
CustomTypeOp::new(
|infcx| {
infcx.register_member_constraints(
param_env,
opaque_type_key,
decl.hidden_type.ty,
decl.hidden_type.span,
);
Ok(InferOk { value: (), obligations: vec![] })
},
|| "opaque_type_map".to_string(),
),
)
.unwrap();
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type.ty);
trace!( trace!(
"finalized opaque type {:?} to {:#?}", "finalized opaque type {:?} to {:#?}",
opaque_type_key, opaque_type_key,
hidden_type.kind() decl.concrete_ty.kind()
); );
if hidden_type.has_infer_types_or_consts() { if decl.concrete_ty.has_infer_types_or_consts() {
infcx.tcx.sess.delay_span_bug( infcx.tcx.sess.delay_span_bug(
decl.hidden_type.span, body.span,
&format!("could not resolve {:#?}", hidden_type.kind()), &format!("could not resolve {:#?}", decl.concrete_ty.kind()),
); );
hidden_type = infcx.tcx.ty_error(); decl.concrete_ty = infcx.tcx.ty_error();
} }
let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind()
{
*def_id == opaque_type_key.def_id
} else {
false
};
(opaque_type_key, (hidden_type, decl.hidden_type.span, decl.origin)) if concrete_is_opaque {
// We're using an opaque `impl Trait` type without
// 'revealing' it. For example, code like this:
//
// type Foo = impl Debug;
// fn foo1() -> Foo { ... }
// fn foo2() -> Foo { foo1() }
//
// In `foo2`, we're not revealing the type of `Foo` - we're
// just treating it as the opaque type.
//
// When this occurs, we do *not* want to try to equate
// the concrete type with the underlying defining type
// of the opaque type - this will always fail, since
// the defining type of an opaque type is always
// some other type (e.g. not itself)
// Essentially, none of the normal obligations apply here -
// we're just passing around some unknown opaque type,
// without actually looking at the underlying type it
// gets 'revealed' into
debug!(
"eq_opaque_type_and_type: non-defining use of {:?}",
opaque_type_key.def_id,
);
None
} else {
Some((opaque_type_key, decl))
}
}) })
.collect() .collect()
}, },
@ -262,7 +274,7 @@ fn type_check_internal<'a, 'tcx, R>(
borrowck_context, borrowck_context,
); );
let errors_reported = { let errors_reported = {
let mut verifier = TypeVerifier::new(&mut checker, promoted); let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
verifier.visit_body(&body); verifier.visit_body(&body);
verifier.errors_reported verifier.errors_reported
}; };
@ -319,6 +331,7 @@ enum FieldAccessError {
/// is a problem. /// is a problem.
struct TypeVerifier<'a, 'b, 'tcx> { struct TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>, cx: &'a mut TypeChecker<'b, 'tcx>,
body: &'b Body<'tcx>,
promoted: &'b IndexVec<Promoted, Body<'tcx>>, promoted: &'b IndexVec<Promoted, Body<'tcx>>,
last_span: Span, last_span: Span,
errors_reported: bool, errors_reported: bool,
@ -454,7 +467,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
self.super_rvalue(rvalue, location); self.super_rvalue(rvalue, location);
let rval_ty = rvalue.ty(self.body(), self.tcx()); let rval_ty = rvalue.ty(self.body, self.tcx());
self.sanitize_type(rvalue, rval_ty); self.sanitize_type(rvalue, rval_ty);
} }
@ -513,13 +526,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
fn new( fn new(
cx: &'a mut TypeChecker<'b, 'tcx>, cx: &'a mut TypeChecker<'b, 'tcx>,
body: &'b Body<'tcx>,
promoted: &'b IndexVec<Promoted, Body<'tcx>>, promoted: &'b IndexVec<Promoted, Body<'tcx>>,
) -> Self { ) -> Self {
TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false } TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false }
}
fn body(&self) -> &Body<'tcx> {
self.cx.body
} }
fn tcx(&self) -> TyCtxt<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> {
@ -544,7 +554,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
) -> PlaceTy<'tcx> { ) -> PlaceTy<'tcx> {
debug!("sanitize_place: {:?}", place); debug!("sanitize_place: {:?}", place);
let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty); let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
for elem in place.projection.iter() { for elem in place.projection.iter() {
if place_ty.variant_index.is_none() { if place_ty.variant_index.is_none() {
@ -589,7 +599,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// checker on the promoted MIR, then transfer the constraints back to // checker on the promoted MIR, then transfer the constraints back to
// the main MIR, changing the locations to the provided location. // the main MIR, changing the locations to the provided location.
let parent_body = mem::replace(&mut self.cx.body, promoted_body); let parent_body = mem::replace(&mut self.body, promoted_body);
// Use new sets of constraints and closure bounds so that we can // Use new sets of constraints and closure bounds so that we can
// modify their locations. // modify their locations.
@ -625,7 +635,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
self.cx.typeck_mir(promoted_body); self.cx.typeck_mir(promoted_body);
} }
self.cx.body = parent_body; self.body = parent_body;
// Merge the outlives constraints back in, at the given location. // Merge the outlives constraints back in, at the given location.
swap_constraints(self); swap_constraints(self);
@ -687,7 +697,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
})) }))
} }
ProjectionElem::Index(i) => { ProjectionElem::Index(i) => {
let index_ty = Place::from(i).ty(self.body(), tcx).ty; let index_ty = Place::from(i).ty(self.body, tcx).ty;
if index_ty != tcx.types.usize { if index_ty != tcx.types.usize {
PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)) PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i))
} else { } else {
@ -896,7 +906,7 @@ struct BorrowCheckContext<'a, 'tcx> {
crate struct MirTypeckResults<'tcx> { crate struct MirTypeckResults<'tcx> {
crate constraints: MirTypeckRegionConstraints<'tcx>, crate constraints: MirTypeckRegionConstraints<'tcx>,
crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, (Ty<'tcx>, Span, OpaqueTyOrigin)>, crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
} }
/// A collection of region constraints that must be satisfied for the /// A collection of region constraints that must be satisfied for the
@ -1046,19 +1056,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
checker checker
} }
fn body(&self) -> &Body<'tcx> {
self.body
}
fn unsized_feature_enabled(&self) -> bool { fn unsized_feature_enabled(&self) -> bool {
let features = self.tcx().features(); let features = self.tcx().features();
features.unsized_locals || features.unsized_fn_params features.unsized_locals || features.unsized_fn_params
} }
/// Equate the inferred type and the annotated type for user type annotations /// Equate the inferred type and the annotated type for user type annotations
#[instrument(skip(self), level = "debug")]
fn check_user_type_annotations(&mut self) { fn check_user_type_annotations(&mut self) {
debug!(?self.user_type_annotations); debug!(
"check_user_type_annotations: user_type_annotations={:?}",
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 inferred_ty = self.normalize(inferred_ty, Locations::All(span));
@ -1199,6 +1207,131 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Ok(()) Ok(())
} }
/// Equates a type `anon_ty` that may contain opaque types whose
/// values are to be inferred by the MIR.
///
/// The type `revealed_ty` contains the same type as `anon_ty`, but with the
/// hidden types for impl traits revealed.
///
/// # Example
///
/// Consider a piece of code like
///
/// ```rust
/// type Foo<U> = impl Debug;
///
/// fn foo<T: Debug>(t: T) -> Box<Foo<T>> {
/// Box::new((t, 22_u32))
/// }
/// ```
///
/// Here, the function signature would be something like
/// `fn(T) -> Box<impl Debug>`. The MIR return slot would have
/// the type with the opaque type revealed, so `Box<(T, u32)>`.
///
/// In terms of our function parameters:
///
/// * `anon_ty` would be `Box<Foo<T>>` where `Foo<T>` is an opaque type
/// scoped to this function (note that it is parameterized by the
/// generics of `foo`). Note that `anon_ty` is not just the opaque type,
/// but the entire return type (which may contain opaque types within it).
/// * `revealed_ty` would be `Box<(T, u32)>`
#[instrument(skip(self), level = "debug")]
fn eq_opaque_type_and_type(
&mut self,
revealed_ty: Ty<'tcx>,
anon_ty: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
// Fast path for the common case.
if !anon_ty.has_opaque_types() {
if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) {
span_mirbug!(
self,
locations,
"eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`",
revealed_ty,
anon_ty,
terr
);
}
return Ok(());
}
let param_env = self.param_env;
let body = self.body;
let mir_def_id = body.source.def_id().expect_local();
debug!(?mir_def_id);
self.fully_perform_op(
locations,
category,
CustomTypeOp::new(
|infcx| {
let mut obligations = ObligationAccumulator::default();
let dummy_body_id = hir::CRATE_HIR_ID;
// Replace the opaque types defined by this function with
// inference variables, creating a map. In our example above,
// this would transform the type `Box<Foo<T>>` (where `Foo` is an opaque type)
// to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`.
// (Note that the key of the map is both the def-id of `Foo` along with
// any generic parameters.)
let output_ty = obligations.add(infcx.instantiate_opaque_types(
dummy_body_id,
param_env,
anon_ty,
locations.span(body),
));
debug!(?output_ty, ?revealed_ty);
// Make sure that the inferred types are well-formed. I'm
// not entirely sure this is needed (the HIR type check
// didn't do this) but it seems sensible to prevent opaque
// types hiding ill-formed types.
obligations.obligations.push(traits::Obligation::new(
ObligationCause::dummy(),
param_env,
ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into()))
.to_predicate(infcx.tcx),
));
obligations.add(
infcx
.at(&ObligationCause::dummy(), param_env)
.eq(output_ty, revealed_ty)?,
);
debug!("equated");
Ok(InferOk { value: (), obligations: obligations.into_vec() })
},
|| "input_output".to_string(),
),
)?;
// Finally, if we instantiated the anon types successfully, we
// have to solve any bounds (e.g., `-> impl Iterator` needs to
// prove that `T: Iterator` where `T` is the type we
// instantiated it with).
let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone();
for (opaque_type_key, opaque_decl) in opaque_type_map {
self.fully_perform_op(
locations,
ConstraintCategory::OpaqueType,
CustomTypeOp::new(
|infcx| {
infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
Ok(InferOk { value: (), obligations: vec![] })
},
|| "opaque_type_map".to_string(),
),
)?;
}
Ok(())
}
fn tcx(&self) -> TyCtxt<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx self.infcx.tcx
} }
@ -2641,31 +2774,19 @@ impl NormalizeLocation for Location {
} }
} }
/// Runs `infcx.instantiate_opaque_types`. Unlike other `TypeOp`s, #[derive(Debug, Default)]
/// this is not canonicalized - it directly affects the main `InferCtxt` struct ObligationAccumulator<'tcx> {
/// that we use during MIR borrowchecking. obligations: PredicateObligations<'tcx>,
#[derive(Debug)]
pub(super) struct InstantiateOpaqueType<'tcx> {
pub base_universe: Option<ty::UniverseIndex>,
pub region_constraints: Option<RegionConstraintData<'tcx>>,
pub obligation: PredicateObligation<'tcx>,
} }
impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> { impl<'tcx> ObligationAccumulator<'tcx> {
type Output = (); fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
/// We use this type itself to store the information used let InferOk { value, obligations } = value;
/// when reporting errors. Since this is not a query, we don't self.obligations.extend(obligations);
/// re-run anything during error reporting - we just use the information value
/// 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<TypeOpOutput<'tcx, Self>> { fn into_vec(self) -> PredicateObligations<'tcx> {
let (mut output, region_constraints) = scrape_region_constraints(infcx, || { self.obligations
Ok(InferOk { value: (), obligations: vec![self.obligation.clone()] })
})?;
self.region_constraints = Some(region_constraints);
output.error_info = Some(self);
Ok(output)
} }
} }

View File

@ -1,15 +1,13 @@
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
use rustc_infer::infer::NllRegionVariableOrigin; use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::ConstraintCategory; use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{self, Const, Ty}; use rustc_middle::ty::{self, Const, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits::query::Fallible; use rustc_trait_selection::traits::query::Fallible;
use crate::constraints::OutlivesConstraint; use crate::constraints::OutlivesConstraint;
use crate::diagnostics::UniverseInfo; use crate::diagnostics::UniverseInfo;
use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker}; use crate::type_check::{Locations, TypeChecker};
impl<'a, 'tcx> TypeChecker<'a, 'tcx> { impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
@ -65,10 +63,6 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
} }
impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
fn span(&self) -> Span {
self.locations.span(self.type_checker.body)
}
fn param_env(&self) -> ty::ParamEnv<'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.type_checker.param_env self.type_checker.param_env
} }
@ -123,9 +117,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
// We don't have to worry about the equality of consts during borrow checking // We don't have to worry about the equality of consts during borrow checking
// as consts always have a static lifetime. // as consts always have a static lifetime.
// FIXME(oli-obk): is this really true? We can at least have HKL and with
// inline consts we may have further lifetimes that may be unsound to treat as
// 'static.
fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {} fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
fn normalization() -> NormalizationStrategy { fn normalization() -> NormalizationStrategy {
@ -135,30 +126,4 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
fn forbid_inference_vars() -> bool { fn forbid_inference_vars() -> bool {
true true
} }
fn register_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool) {
let param_env = self.param_env();
let span = self.span();
let def_id = self.type_checker.body.source.def_id().expect_local();
let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
let cause = ObligationCause::misc(span, body_id);
self.type_checker
.fully_perform_op(
self.locations,
self.category,
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();
}
} }

View File

@ -728,7 +728,6 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin)) self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin))
} }
#[instrument(level = "debug", skip(self, indices))]
fn replace_bound_regions_with_nll_infer_vars<T>( fn replace_bound_regions_with_nll_infer_vars<T>(
&self, &self,
origin: NllRegionVariableOrigin, origin: NllRegionVariableOrigin,
@ -739,15 +738,22 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
where where
T: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>,
{ {
debug!(
"replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})",
value, all_outlive_scope,
);
let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
debug!(?br); debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: all_outlive_scope.to_def_id(), scope: all_outlive_scope.to_def_id(),
bound_region: br.kind, bound_region: br.kind,
})); }));
let region_vid = self.next_nll_region_var(origin); let region_vid = self.next_nll_region_var(origin);
indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid()); indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
debug!(?liberated_region, ?region_vid); debug!(
"replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}",
liberated_region, region_vid
);
region_vid region_vid
}); });
value value
@ -762,7 +768,6 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
/// entries for them and store them in the indices map. This code iterates over the complete /// entries for them and store them in the indices map. This code iterates over the complete
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the /// set of late-bound regions and checks for any that we have not yet seen, adding them to the
/// inputs vector. /// inputs vector.
#[instrument(skip(self, indices))]
fn replace_late_bound_regions_with_nll_infer_vars( fn replace_late_bound_regions_with_nll_infer_vars(
&self, &self,
mir_def_id: LocalDefId, mir_def_id: LocalDefId,
@ -774,7 +779,6 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r); debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
if !indices.indices.contains_key(&r) { if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR); let region_vid = self.next_nll_region_var(FR);
debug!(?region_vid);
indices.insert_late_bound_region(r, region_vid.to_region_vid()); indices.insert_late_bound_region(r, region_vid.to_region_vid());
} }
}); });

View File

@ -11,7 +11,7 @@ use rustc_middle::mir::*;
use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable}; use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
use rustc_mir_dataflow::{self, Analysis}; use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol}; use rustc_span::{sym, Span, Symbol};
use rustc_trait_selection::traits::SelectionContext; use rustc_trait_selection::traits::SelectionContext;
@ -46,10 +46,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
location: Location, location: Location,
) -> bool { ) -> bool {
let ty = ccx.body.local_decls[local].ty; let ty = ccx.body.local_decls[local].ty;
// Peeking into opaque types causes cycles if the current function declares said opaque if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
// type. Thus we avoid short circuiting on the type and instead run the more expensive
// analysis that looks at the actual usage within this function
if !ty.has_opaque_types() && !NeedsDrop::in_any_value_of_ty(ccx, ty) {
return false; return false;
} }
@ -103,10 +100,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
location: Location, location: Location,
) -> bool { ) -> bool {
let ty = ccx.body.local_decls[local].ty; let ty = ccx.body.local_decls[local].ty;
// Peeking into opaque types causes cycles if the current function declares said opaque if !HasMutInterior::in_any_value_of_ty(ccx, ty) {
// type. Thus we avoid short circuiting on the type and instead run the more expensive
// analysis that looks at the actual usage within this function
if !ty.has_opaque_types() && !HasMutInterior::in_any_value_of_ty(ccx, ty) {
return false; return false;
} }
@ -154,12 +148,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
// If we know that all values of the return type are structurally matchable, there's no // If we know that all values of the return type are structurally matchable, there's no
// need to run dataflow. // need to run dataflow.
// Opaque types do not participate in const generics or pattern matching, so we can safely count them out. _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false,
_ if ccx.body.return_ty().has_opaque_types()
|| !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
{
false
}
hir::ConstContext::Const | hir::ConstContext::Static(_) => { hir::ConstContext::Const | hir::ConstContext::Static(_) => {
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx) let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
@ -406,7 +395,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
| ty::PredicateKind::Projection(_) | ty::PredicateKind::Projection(_)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
ty::PredicateKind::ObjectSafe(_) => { ty::PredicateKind::ObjectSafe(_) => {
bug!("object safe predicate on function: {:#?}", predicate) bug!("object safe predicate on function: {:#?}", predicate)

View File

@ -79,6 +79,7 @@ pub fn equal_up_to_regions<'tcx>(
} }
// Normalize lifetimes away on both sides, then compare. // Normalize lifetimes away on both sides, then compare.
let param_env = param_env.with_reveal_all_normalized(tcx);
let normalize = |ty: Ty<'tcx>| { let normalize = |ty: Ty<'tcx>| {
tcx.normalize_erasing_regions( tcx.normalize_erasing_regions(
param_env, param_env,
@ -170,7 +171,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
return true; return true;
} }
// Normalize projections and things like that. // Normalize projections and things like that.
let param_env = self.param_env; // FIXME: We need to reveal_all, as some optimizations change types in ways
// that require unfolding opaque types.
let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
let src = self.tcx.normalize_erasing_regions(param_env, src); let src = self.tcx.normalize_erasing_regions(param_env, src);
let dest = self.tcx.normalize_erasing_regions(param_env, dest); let dest = self.tcx.normalize_erasing_regions(param_env, dest);

View File

@ -30,11 +30,6 @@ where
} }
} }
/// Removes the entry from the map and returns the removed value
pub fn remove(&mut self, k: &K) -> Option<V> {
self.0.iter().position(|(k2, _)| k2 == k).map(|pos| self.0.remove(pos).1)
}
/// Gets a reference to the value in the entry. /// Gets a reference to the value in the entry.
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where where
@ -44,15 +39,6 @@ where
self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1) self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
} }
/// Gets a mutable reference to the value in the entry.
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Eq,
{
self.0.iter_mut().find(|(key, _)| k == key.borrow()).map(|elem| &mut elem.1)
}
/// Returns the any value corresponding to the supplied predicate filter. /// Returns the any value corresponding to the supplied predicate filter.
/// ///
/// The supplied predicate will be applied to each (key, value) pair and it will return a /// The supplied predicate will be applied to each (key, value) pair and it will return a
@ -72,7 +58,7 @@ where
// This should return just one element, otherwise it's a bug // This should return just one element, otherwise it's a bug
assert!( assert!(
filter.next().is_none(), filter.next().is_none(),
"Collection {:#?} should have just one matching element", "Collection {:?} should have just one matching element",
self self
); );
Some(value) Some(value)

View File

@ -34,12 +34,6 @@ pub struct At<'a, 'tcx> {
pub infcx: &'a InferCtxt<'a, 'tcx>, pub infcx: &'a InferCtxt<'a, 'tcx>,
pub cause: &'a ObligationCause<'tcx>, pub cause: &'a ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>, pub param_env: ty::ParamEnv<'tcx>,
/// Whether we should define opaque types
/// or just treat them opaquely.
/// Currently only used to prevent predicate
/// matching from matching anything against opaque
/// types.
pub define_opaque_types: bool,
} }
pub struct Trace<'a, 'tcx> { pub struct Trace<'a, 'tcx> {
@ -55,7 +49,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
cause: &'a ObligationCause<'tcx>, cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> At<'a, 'tcx> { ) -> At<'a, 'tcx> {
At { infcx: self, cause, param_env, define_opaque_types: true } At { infcx: self, cause, param_env }
} }
} }
@ -70,10 +64,6 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
} }
impl<'a, 'tcx> At<'a, 'tcx> { impl<'a, 'tcx> At<'a, 'tcx> {
pub fn define_opaque_types(self, define_opaque_types: bool) -> Self {
Self { define_opaque_types, ..self }
}
/// Hacky routine for equating two impl headers in coherence. /// Hacky routine for equating two impl headers in coherence.
pub fn eq_impl_headers( pub fn eq_impl_headers(
self, self,
@ -204,7 +194,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields fields
.sub(a_is_expected) .sub(a_is_expected)
.relate(a, b) .relate(a, b)
@ -221,7 +211,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields fields
.equate(a_is_expected) .equate(a_is_expected)
.relate(a, b) .relate(a, b)
@ -236,7 +226,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields fields
.lub(a_is_expected) .lub(a_is_expected)
.relate(a, b) .relate(a, b)
@ -251,7 +241,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields fields
.glb(a_is_expected) .glb(a_is_expected)
.relate(a, b) .relate(a, b)

View File

@ -26,7 +26,6 @@ use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt};
use rustc_span::Span;
use std::fmt::Debug; use std::fmt::Debug;
use std::iter; use std::iter;
@ -90,7 +89,6 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
var_values: inference_vars, var_values: inference_vars,
region_constraints: QueryRegionConstraints::default(), region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Proven, // Ambiguities are OK! certainty: Certainty::Proven, // Ambiguities are OK!
opaque_types: vec![],
value: answer, value: answer,
}) })
} }
@ -135,27 +133,14 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
let certainty = let certainty =
if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
let opaque_types = self.take_opaque_types_for_query_response();
Ok(QueryResponse { Ok(QueryResponse {
var_values: inference_vars, var_values: inference_vars,
region_constraints, region_constraints,
certainty, certainty,
value: answer, value: answer,
opaque_types,
}) })
} }
fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
self.inner
.borrow_mut()
.opaque_type_storage
.take_opaque_types()
.into_iter()
.map(|(k, v)| (self.tcx.mk_opaque(k.def_id, k.substs), v.hidden_type.ty))
.collect()
}
/// Given the (canonicalized) result to a canonical query, /// Given the (canonicalized) result to a canonical query,
/// instantiates the result so it can be used, plugging in the /// instantiates the result so it can be used, plugging in the
/// values from the canonical query. (Note that the result may /// values from the canonical query. (Note that the result may
@ -238,12 +223,13 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
where where
R: Debug + TypeFoldable<'tcx>, R: Debug + TypeFoldable<'tcx>,
{ {
let InferOk { value: result_subst, mut obligations } = self let result_subst =
.query_response_substitution_guess(cause, param_env, original_values, query_response)?; self.query_response_substitution_guess(cause, original_values, query_response);
// Compute `QueryOutlivesConstraint` values that unify each of // Compute `QueryOutlivesConstraint` values that unify each of
// the original values `v_o` that was canonicalized into a // the original values `v_o` that was canonicalized into a
// variable... // variable...
let mut obligations = vec![];
for (index, original_value) in original_values.var_values.iter().enumerate() { for (index, original_value) in original_values.var_values.iter().enumerate() {
// ...with the value `v_r` of that variable from the query. // ...with the value `v_r` of that variable from the query.
@ -358,25 +344,20 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
original_values, query_response, original_values, query_response,
); );
let mut value = self.query_response_substitution_guess( let result_subst =
cause, self.query_response_substitution_guess(cause, original_values, query_response);
param_env,
original_values,
query_response,
)?;
value.obligations.extend( let obligations = self
self.unify_query_response_substitution_guess( .unify_query_response_substitution_guess(
cause, cause,
param_env, param_env,
original_values, original_values,
&value.value, &result_subst,
query_response, query_response,
)? )?
.into_obligations(), .into_obligations();
);
Ok(value) Ok(InferOk { value: result_subst, obligations })
} }
/// Given the original values and the (canonicalized) result from /// Given the original values and the (canonicalized) result from
@ -391,10 +372,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
fn query_response_substitution_guess<R>( fn query_response_substitution_guess<R>(
&self, &self,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
original_values: &OriginalQueryValues<'tcx>, original_values: &OriginalQueryValues<'tcx>,
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
) -> InferResult<'tcx, CanonicalVarValues<'tcx>> ) -> CanonicalVarValues<'tcx>
where where
R: Debug + TypeFoldable<'tcx>, R: Debug + TypeFoldable<'tcx>,
{ {
@ -494,16 +474,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
.collect(), .collect(),
}; };
let mut obligations = vec![]; result_subst
// Carry all newly resolved opaque types to the caller's scope
for &(a, b) in &query_response.value.opaque_types {
let a = substitute_value(self.tcx, &result_subst, a);
let b = substitute_value(self.tcx, &result_subst, b);
obligations.extend(self.handle_opaque_type(a, b, cause, param_env)?.obligations);
}
Ok(InferOk { value: result_subst, obligations })
} }
/// Given a "guess" at the values for the canonical variables in /// Given a "guess" at the values for the canonical variables in
@ -660,10 +631,6 @@ struct QueryTypeRelatingDelegate<'a, 'tcx> {
} }
impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
fn span(&self) -> Span {
self.cause.span
}
fn param_env(&self) -> ty::ParamEnv<'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env self.param_env
} }
@ -719,14 +686,4 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
fn forbid_inference_vars() -> bool { fn forbid_inference_vars() -> bool {
true true
} }
fn register_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool) {
self.obligations.push(self.infcx.opaque_ty_obligation(
a,
b,
a_is_expected,
self.param_env,
self.cause.clone(),
));
}
} }

View File

@ -51,12 +51,6 @@ pub struct CombineFields<'infcx, 'tcx> {
pub cause: Option<ty::relate::Cause>, pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'tcx>, pub param_env: ty::ParamEnv<'tcx>,
pub obligations: PredicateObligations<'tcx>, pub obligations: PredicateObligations<'tcx>,
/// Whether we should define opaque types
/// or just treat them opaquely.
/// Currently only used to prevent predicate
/// matching from matching anything against opaque
/// types.
pub define_opaque_types: bool,
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -328,7 +322,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
/// will first instantiate `b_vid` with a *generalized* version /// will first instantiate `b_vid` with a *generalized* version
/// of `a_ty`. Generalization introduces other inference /// of `a_ty`. Generalization introduces other inference
/// variables wherever subtyping could occur. /// variables wherever subtyping could occur.
#[instrument(skip(self), level = "debug")]
pub fn instantiate( pub fn instantiate(
&mut self, &mut self,
a_ty: Ty<'tcx>, a_ty: Ty<'tcx>,
@ -341,6 +334,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
// Get the actual variable that b_vid has been inferred to // Get the actual variable that b_vid has been inferred to
debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown()); debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid);
// Generalize type of `a_ty` appropriately depending on the // Generalize type of `a_ty` appropriately depending on the
// direction. As an example, assume: // direction. As an example, assume:
// //
@ -353,7 +348,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
// variables. (Down below, we will relate `a_ty <: b_ty`, // variables. (Down below, we will relate `a_ty <: b_ty`,
// adding constraints like `'x: '?2` and `?1 <: ?3`.) // adding constraints like `'x: '?2` and `?1 <: ?3`.)
let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?; let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
debug!(?b_ty); debug!(
"instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})",
a_ty, dir, b_vid, b_ty
);
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty); self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
if needs_wf { if needs_wf {
@ -394,13 +392,13 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
/// Preconditions: /// Preconditions:
/// ///
/// - `for_vid` is a "root vid" /// - `for_vid` is a "root vid"
#[instrument(skip(self), level = "trace")]
fn generalize( fn generalize(
&self, &self,
ty: Ty<'tcx>, ty: Ty<'tcx>,
for_vid: ty::TyVid, for_vid: ty::TyVid,
dir: RelationDir, dir: RelationDir,
) -> RelateResult<'tcx, Generalization<'tcx>> { ) -> RelateResult<'tcx, Generalization<'tcx>> {
debug!("generalize(ty={:?}, for_vid={:?}, dir={:?}", ty, for_vid, dir);
// Determine the ambient variance within which `ty` appears. // Determine the ambient variance within which `ty` appears.
// The surrounding equation is: // The surrounding equation is:
// //
@ -414,7 +412,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
RelationDir::SupertypeOf => ty::Contravariant, RelationDir::SupertypeOf => ty::Contravariant,
}; };
trace!(?ambient_variance); debug!("generalize: ambient_variance = {:?}", ambient_variance);
let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) { let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
v @ TypeVariableValue::Known { .. } => { v @ TypeVariableValue::Known { .. } => {
@ -423,8 +421,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
TypeVariableValue::Unknown { universe } => universe, TypeVariableValue::Unknown { universe } => universe,
}; };
trace!(?for_universe); debug!("generalize: for_universe = {:?}", for_universe);
trace!(?self.trace); debug!("generalize: trace = {:?}", self.trace);
let mut generalize = Generalizer { let mut generalize = Generalizer {
infcx: self.infcx, infcx: self.infcx,
@ -441,12 +439,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
let ty = match generalize.relate(ty, ty) { let ty = match generalize.relate(ty, ty) {
Ok(ty) => ty, Ok(ty) => ty,
Err(e) => { Err(e) => {
debug!(?e, "failure"); debug!("generalize: failure {:?}", e);
return Err(e); return Err(e);
} }
}; };
let needs_wf = generalize.needs_wf; let needs_wf = generalize.needs_wf;
trace!(?ty, ?needs_wf, "success"); debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf);
Ok(Generalization { ty, needs_wf }) Ok(Generalization { ty, needs_wf })
} }

View File

@ -66,19 +66,18 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
self.relate(a, b) self.relate(a, b)
} }
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
if a == b { if a == b {
return Ok(a); return Ok(a);
} }
trace!(a = ?a.kind(), b = ?b.kind());
let infcx = self.fields.infcx; let infcx = self.fields.infcx;
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b);
match (a.kind(), b.kind()) { match (a.kind(), b.kind()) {
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
infcx.inner.borrow_mut().type_variables().equate(a_id, b_id); infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
@ -92,21 +91,6 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
} }
(&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
self.fields.infcx.super_combine_tys(self, a, b)?;
}
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
if self.fields.define_opaque_types && did.is_local() =>
{
self.fields.obligations.push(infcx.opaque_ty_obligation(
a,
b,
self.a_is_expected(),
self.param_env(),
self.fields.trace.cause.clone(),
));
}
_ => { _ => {
self.fields.infcx.super_combine_tys(self, a, b)?; self.fields.infcx.super_combine_tys(self, a, b)?;
} }

View File

@ -4,7 +4,7 @@ use super::InferCtxt;
use super::Subtype; use super::Subtype;
use crate::infer::combine::ConstEquateRelation; use crate::infer::combine::ConstEquateRelation;
use crate::traits::{ObligationCause, PredicateObligation}; use crate::traits::ObligationCause;
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
@ -111,20 +111,12 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
&self.fields.trace.cause &self.fields.trace.cause
} }
fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
self.fields.obligations.extend(obligations)
}
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let mut sub = self.fields.sub(self.a_is_expected); let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(v, a)?; sub.relate(v, a)?;
sub.relate(v, b)?; sub.relate(v, b)?;
Ok(()) Ok(())
} }
fn define_opaque_types(&self) -> bool {
self.fields.define_opaque_types
}
} }
impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> { impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {

View File

@ -22,7 +22,7 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferCtxt; use super::InferCtxt;
use crate::traits::{ObligationCause, PredicateObligation}; use crate::traits::ObligationCause;
use rustc_middle::ty::relate::{RelateResult, TypeRelation}; use rustc_middle::ty::relate::{RelateResult, TypeRelation};
use rustc_middle::ty::TyVar; use rustc_middle::ty::TyVar;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
@ -32,10 +32,6 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
fn cause(&self) -> &ObligationCause<'tcx>; fn cause(&self) -> &ObligationCause<'tcx>;
fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>);
fn define_opaque_types(&self) -> bool;
// Relates the type `v` to `a` and `b` such that `v` represents // Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate. // the LUB/GLB of `a` and `b` as appropriate.
// //
@ -45,7 +41,6 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
} }
#[instrument(skip(this), level = "debug")]
pub fn super_lattice_tys<'a, 'tcx: 'a, L>( pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
this: &mut L, this: &mut L,
a: Ty<'tcx>, a: Ty<'tcx>,
@ -54,17 +49,15 @@ pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
where where
L: LatticeDir<'a, 'tcx>, L: LatticeDir<'a, 'tcx>,
{ {
debug!("{}", this.tag()); debug!("{}.lattice_tys({:?}, {:?})", this.tag(), a, b);
if a == b { if a == b {
return Ok(a); return Ok(a);
} }
let infcx = this.infcx(); let infcx = this.infcx();
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
match (a.kind(), b.kind()) { match (a.kind(), b.kind()) {
// If one side is known to be a variable and one is not, // If one side is known to be a variable and one is not,
// create a variable (`v`) to represent the LUB. Make sure to // create a variable (`v`) to represent the LUB. Make sure to
@ -101,22 +94,6 @@ where
Ok(v) Ok(v)
} }
(&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
infcx.super_combine_tys(this, a, b)
}
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
if this.define_opaque_types() && did.is_local() =>
{
this.add_obligations(vec![infcx.opaque_ty_obligation(
a,
b,
this.a_is_expected(),
this.param_env(),
this.cause().clone(),
)]);
Ok(a)
}
_ => infcx.super_combine_tys(this, a, b), _ => infcx.super_combine_tys(this, a, b),
} }
} }

View File

@ -4,7 +4,7 @@ use super::InferCtxt;
use super::Subtype; use super::Subtype;
use crate::infer::combine::ConstEquateRelation; use crate::infer::combine::ConstEquateRelation;
use crate::traits::{ObligationCause, PredicateObligation}; use crate::traits::ObligationCause;
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
@ -117,18 +117,10 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
&self.fields.trace.cause &self.fields.trace.cause
} }
fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
self.fields.obligations.extend(obligations)
}
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let mut sub = self.fields.sub(self.a_is_expected); let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(a, v)?; sub.relate(a, v)?;
sub.relate(b, v)?; sub.relate(b, v)?;
Ok(()) Ok(())
} }
fn define_opaque_types(&self) -> bool {
self.fields.define_opaque_types
}
} }

View File

@ -5,7 +5,7 @@ pub use self::RegionVariableOrigin::*;
pub use self::SubregionOrigin::*; pub use self::SubregionOrigin::*;
pub use self::ValuePairs::*; pub use self::ValuePairs::*;
use self::opaque_types::OpaqueTypeStorage; use self::opaque_types::OpaqueTypeMap;
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
@ -192,8 +192,18 @@ pub struct InferCtxtInner<'tcx> {
undo_log: InferCtxtUndoLogs<'tcx>, undo_log: InferCtxtUndoLogs<'tcx>,
/// Caches for opaque type inference. // Opaque types found in explicit return types and their
pub opaque_type_storage: OpaqueTypeStorage<'tcx>, // associated fresh inference variable. Writeback resolves these
// variables to get the concrete type, which can be used to
// 'de-opaque' OpaqueTypeDecl outside of type inference.
pub opaque_types: OpaqueTypeMap<'tcx>,
/// A map from inference variables created from opaque
/// type instantiations (`ty::Infer`) to the actual opaque
/// type (`ty::Opaque`). Used during fallback to map unconstrained
/// opaque type inference variables to their corresponding
/// opaque type.
pub opaque_types_vars: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
} }
impl<'tcx> InferCtxtInner<'tcx> { impl<'tcx> InferCtxtInner<'tcx> {
@ -207,7 +217,8 @@ impl<'tcx> InferCtxtInner<'tcx> {
float_unification_storage: ut::UnificationTableStorage::new(), float_unification_storage: ut::UnificationTableStorage::new(),
region_constraint_storage: Some(RegionConstraintStorage::new()), region_constraint_storage: Some(RegionConstraintStorage::new()),
region_obligations: vec![], region_obligations: vec![],
opaque_type_storage: Default::default(), opaque_types: Default::default(),
opaque_types_vars: Default::default(),
} }
} }
@ -226,11 +237,6 @@ impl<'tcx> InferCtxtInner<'tcx> {
self.type_variable_storage.with_log(&mut self.undo_log) self.type_variable_storage.with_log(&mut self.undo_log)
} }
#[inline]
pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
self.opaque_type_storage.with_log(&mut self.undo_log)
}
#[inline] #[inline]
fn int_unification_table( fn int_unification_table(
&mut self, &mut self,
@ -291,10 +297,6 @@ pub struct InferCtxt<'a, 'tcx> {
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck. /// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
pub defining_use_anchor: Option<LocalDefId>, pub defining_use_anchor: Option<LocalDefId>,
/// Used by WF-checking to not have to figure out hidden types itself, but
/// to just invoke type_of to get the already computed hidden type from typeck.
pub reveal_defining_opaque_types: bool,
/// During type-checking/inference of a body, `in_progress_typeck_results` /// During type-checking/inference of a body, `in_progress_typeck_results`
/// contains a reference to the typeck results being built up, which are /// contains a reference to the typeck results being built up, which are
/// used for reading closure kinds/signatures as they are inferred, /// used for reading closure kinds/signatures as they are inferred,
@ -563,7 +565,6 @@ pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>, fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
defining_use_anchor: Option<LocalDefId>, defining_use_anchor: Option<LocalDefId>,
reveal_defining_opaque_types: bool,
} }
pub trait TyCtxtInferExt<'tcx> { pub trait TyCtxtInferExt<'tcx> {
@ -572,12 +573,7 @@ pub trait TyCtxtInferExt<'tcx> {
impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
InferCtxtBuilder { InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
tcx: self,
defining_use_anchor: None,
fresh_typeck_results: None,
reveal_defining_opaque_types: false,
}
} }
} }
@ -601,13 +597,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
self self
} }
/// WF-checking doesn't need to recompute opaque types and can instead use
/// the type_of query to get them from typeck.
pub fn reveal_defining_opaque_types(mut self) -> Self {
self.reveal_defining_opaque_types = true;
self
}
/// Given a canonical value `C` as a starting point, create an /// Given a canonical value `C` as a starting point, create an
/// inference context that contains each of the bound values /// inference context that contains each of the bound values
/// within instantiated as a fresh variable. The `f` closure is /// within instantiated as a fresh variable. The `f` closure is
@ -632,17 +621,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
} }
pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R { pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
let InferCtxtBuilder { let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
tcx,
defining_use_anchor,
reveal_defining_opaque_types,
ref fresh_typeck_results,
} = *self;
let in_progress_typeck_results = fresh_typeck_results.as_ref(); let in_progress_typeck_results = fresh_typeck_results.as_ref();
f(InferCtxt { f(InferCtxt {
tcx, tcx,
defining_use_anchor, defining_use_anchor,
reveal_defining_opaque_types,
in_progress_typeck_results, in_progress_typeck_results,
inner: RefCell::new(InferCtxtInner::new()), inner: RefCell::new(InferCtxtInner::new()),
lexical_region_resolutions: RefCell::new(None), lexical_region_resolutions: RefCell::new(None),
@ -764,7 +747,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
&'a self, &'a self,
trace: TypeTrace<'tcx>, trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
define_opaque_types: bool,
) -> CombineFields<'a, 'tcx> { ) -> CombineFields<'a, 'tcx> {
CombineFields { CombineFields {
infcx: self, infcx: self,
@ -772,7 +754,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
cause: None, cause: None,
param_env, param_env,
obligations: PredicateObligations::new(), obligations: PredicateObligations::new(),
define_opaque_types,
} }
} }
@ -1088,20 +1069,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.tcx.mk_ty_var(self.next_ty_var_id(origin)) self.tcx.mk_ty_var(self.next_ty_var_id(origin))
} }
pub fn next_ty_var_id_in_universe(
&self,
origin: TypeVariableOrigin,
universe: ty::UniverseIndex,
) -> TyVid {
self.inner.borrow_mut().type_variables().new_var(universe, origin)
}
pub fn next_ty_var_in_universe( pub fn next_ty_var_in_universe(
&self, &self,
origin: TypeVariableOrigin, origin: TypeVariableOrigin,
universe: ty::UniverseIndex, universe: ty::UniverseIndex,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let vid = self.next_ty_var_id_in_universe(origin, universe); let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin);
self.tcx.mk_ty_var(vid) self.tcx.mk_ty_var(vid)
} }

View File

@ -24,13 +24,11 @@
use crate::infer::combine::ConstEquateRelation; use crate::infer::combine::ConstEquateRelation;
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue}; use crate::infer::{ConstVarValue, ConstVariableValue};
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::error::TypeError; use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor}; use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
use rustc_span::Span;
use std::fmt::Debug; use std::fmt::Debug;
use std::ops::ControlFlow; use std::ops::ControlFlow;
@ -77,7 +75,6 @@ where
pub trait TypeRelatingDelegate<'tcx> { pub trait TypeRelatingDelegate<'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx>; fn param_env(&self) -> ty::ParamEnv<'tcx>;
fn span(&self) -> Span;
/// Push a constraint `sup: sub` -- this constraint must be /// Push a constraint `sup: sub` -- this constraint must be
/// satisfied for the two types to be related. `sub` and `sup` may /// satisfied for the two types to be related. `sub` and `sup` may
@ -90,8 +87,6 @@ pub trait TypeRelatingDelegate<'tcx> {
info: ty::VarianceDiagInfo<'tcx>, info: ty::VarianceDiagInfo<'tcx>,
); );
fn register_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool);
fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>); fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
/// Creates a new universe index. Used when instantiating placeholders. /// Creates a new universe index. Used when instantiating placeholders.
@ -282,6 +277,7 @@ where
projection_ty: ty::ProjectionTy<'tcx>, projection_ty: ty::ProjectionTy<'tcx>,
value_ty: Ty<'tcx>, value_ty: Ty<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
match *value_ty.kind() { match *value_ty.kind() {
@ -290,8 +286,6 @@ where
kind: TypeVariableOriginKind::MiscVariable, kind: TypeVariableOriginKind::MiscVariable,
span: DUMMY_SP, span: DUMMY_SP,
}); });
// FIXME(lazy-normalization): This will always ICE, because the recursive
// call will end up in the _ arm below.
self.relate_projection_ty(projection_ty, var); self.relate_projection_ty(projection_ty, var);
self.relate_projection_ty(other_projection_ty, var); self.relate_projection_ty(other_projection_ty, var);
var var
@ -537,8 +531,6 @@ where
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
let infcx = self.infcx;
let a = self.infcx.shallow_resolve(a); let a = self.infcx.shallow_resolve(a);
if !D::forbid_inference_vars() { if !D::forbid_inference_vars() {
@ -567,35 +559,6 @@ where
(&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)), (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
(&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
self.infcx.super_combine_tys(self, a, b)
}
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => {
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
let mut generalize = |ty, ty_is_expected| {
let var = infcx.next_ty_var_id_in_universe(
TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: self.delegate.span(),
},
ty::UniverseIndex::ROOT,
);
if ty_is_expected {
self.relate_ty_var((ty, var))
} else {
self.relate_ty_var((var, ty))
}
};
let (a, b) = match (a.kind(), b.kind()) {
(&ty::Opaque(..), _) => (a, generalize(b, false)?),
(_, &ty::Opaque(..)) => (generalize(a, true)?, b),
_ => unreachable!(),
};
self.delegate.register_opaque_type(a, b, true);
trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
Ok(a)
}
(&ty::Projection(projection_ty), _) (&ty::Projection(projection_ty), _)
if D::normalization() == NormalizationStrategy::Lazy => if D::normalization() == NormalizationStrategy::Lazy =>
{ {

View File

@ -1,11 +1,10 @@
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk}; use crate::infer::{InferCtxt, InferOk};
use crate::traits::{self, PredicateObligation}; use crate::traits;
use hir::def_id::{DefId, LocalDefId};
use hir::OpaqueTyOrigin;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap; use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::traits::ObligationCause; use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::subst::{GenericArgKind, Subst}; use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
@ -15,28 +14,14 @@ use std::ops::ControlFlow;
pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>; pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
mod table;
pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
use super::InferResult;
/// Information about the opaque types whose values we /// Information about the opaque types whose values we
/// are inferring in this function (these are the `impl Trait` that /// are inferring in this function (these are the `impl Trait` that
/// appear in the return type). /// appear in the return type).
#[derive(Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct OpaqueTypeDecl<'tcx> { pub struct OpaqueTypeDecl<'tcx> {
/// The hidden types that have been inferred for this opaque type. /// The opaque type (`ty::Opaque`) for this declaration.
/// There can be multiple, but they are all `lub`ed together at the end pub opaque_type: Ty<'tcx>,
/// to obtain the canonical hidden type.
pub hidden_type: OpaqueHiddenType<'tcx>,
/// The origin of the opaque type.
pub origin: hir::OpaqueTyOrigin,
}
#[derive(Copy, Clone, Debug, TypeFoldable)]
pub struct OpaqueHiddenType<'tcx> {
/// The span of this particular definition of the opaque type. So /// The span of this particular definition of the opaque type. So
/// for example: /// for example:
/// ///
@ -50,7 +35,7 @@ pub struct OpaqueHiddenType<'tcx> {
/// In cases where the fn returns `(impl Trait, impl Trait)` or /// In cases where the fn returns `(impl Trait, impl Trait)` or
/// other such combinations, the result is currently /// other such combinations, the result is currently
/// over-approximated, but better than nothing. /// over-approximated, but better than nothing.
pub span: Span, pub definition_span: Span,
/// The type variable that represents the value of the opaque type /// The type variable that represents the value of the opaque type
/// that we require. In other words, after we compile this function, /// that we require. In other words, after we compile this function,
@ -64,132 +49,54 @@ pub struct OpaqueHiddenType<'tcx> {
/// those that are arguments to `Foo` in the constraint above. (In /// those that are arguments to `Foo` in the constraint above. (In
/// other words, `?C` should not include `'b`, even though it's a /// other words, `?C` should not include `'b`, even though it's a
/// lifetime parameter on `foo`.) /// lifetime parameter on `foo`.)
pub ty: Ty<'tcx>, pub concrete_ty: Ty<'tcx>,
/// The origin of the opaque type.
pub origin: hir::OpaqueTyOrigin,
} }
impl<'a, 'tcx> InferCtxt<'a, 'tcx> { impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn handle_opaque_type( /// Replaces all opaque types in `value` with fresh inference variables
/// and creates appropriate obligations. For example, given the input:
///
/// impl Iterator<Item = impl Debug>
///
/// this method would create two type variables, `?0` and `?1`. It would
/// return the type `?0` but also the obligations:
///
/// ?0: Iterator<Item = ?1>
/// ?1: Debug
///
/// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
/// info about the `impl Iterator<..>` type and `?1` to info about
/// the `impl Debug` type.
///
/// # Parameters
///
/// - `parent_def_id` -- the `DefId` of the function in which the opaque type
/// is defined
/// - `body_id` -- the body-id with which the resulting obligations should
/// be associated
/// - `param_env` -- the in-scope parameter environment to be used for
/// obligations
/// - `value` -- the value within which we are instantiating opaque types
/// - `value_span` -- the span where the value came from, used in error reporting
pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
&self, &self,
a: Ty<'tcx>, body_id: hir::HirId,
b: Ty<'tcx>,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> InferResult<'tcx, ()> { value: T,
if a.references_error() || b.references_error() { value_span: Span,
return Ok(InferOk { value: (), obligations: vec![] }); ) -> InferOk<'tcx, T> {
} debug!(
if self.defining_use_anchor.is_some() { "instantiate_opaque_types(value={:?}, body_id={:?}, \
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { param_env={:?}, value_span={:?})",
ty::Opaque(def_id, substs) => { value, body_id, param_env, value_span,
if let ty::Opaque(did2, _) = *b.kind() { );
// We could accept this, but there are various ways to handle this situation, and we don't let mut instantiator =
// want to make a decision on it right now. Likely this case is so super rare anyway, that Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
// no one encounters it in practice. let value = instantiator.instantiate_opaque_types_in_map(value);
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, InferOk { value, obligations: instantiator.obligations }
// where it is of no concern, so we only check for TAITs.
if let Some(OpaqueTyOrigin::TyAlias) =
self.opaque_type_origin(did2, cause.span)
{
self.tcx
.sess
.struct_span_err(
cause.span,
"opaque type's hidden type cannot be another opaque type from the same scope",
)
.span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope")
.span_note(
self.tcx.def_span(def_id),
"opaque type whose hidden type is being assigned",
)
.span_note(
self.tcx.def_span(did2),
"opaque type being used as hidden type",
)
.emit();
}
}
Some(self.register_hidden_type(
OpaqueTypeKey { def_id, substs },
cause.clone(),
param_env,
b,
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
// value we are inferring. At present, this is
// always true during the first phase of
// type-check, but not always true later on during
// NLL. Once we support named opaque types more fully,
// this same scenario will be able to arise during all phases.
//
// Here is an example using type alias `impl Trait`
// that indicates the distinction we are checking for:
//
// ```rust
// mod a {
// pub type Foo = impl Iterator;
// pub fn make_foo() -> Foo { .. }
// }
//
// mod b {
// fn foo() -> a::Foo { a::make_foo() }
// }
// ```
//
// Here, the return type of `foo` references an
// `Opaque` indeed, but not one whose value is
// presently being inferred. You can get into a
// similar situation with closure return types
// today:
//
// ```rust
// fn foo() -> impl Iterator { .. }
// fn bar() {
// let x = || foo(); // returns the Opaque assoc with `foo`
// }
// ```
self.opaque_type_origin(def_id, cause.span)?,
))
}
_ => None,
};
if let Some(res) = process(a, b) {
res
} else if let Some(res) = process(b, a) {
res
} else {
// Rerun equality check, but this time error out due to
// different types.
match self.at(cause, param_env).define_opaque_types(false).eq(a, b) {
Ok(_) => span_bug!(
cause.span,
"opaque types are never equal to anything but themselves: {:#?}",
(a, b)
),
Err(e) => Err(e),
}
}
} else {
let (opaque_type, hidden_ty) = match (a.kind(), b.kind()) {
(ty::Opaque(..), _) => (a, b),
(_, ty::Opaque(..)) => (b, a),
types => span_bug!(
cause.span,
"opaque type obligations only work for opaque types: {:#?}",
types
),
};
let key = opaque_type.expect_opaque_type();
let origin = self.opaque_ty_origin_unchecked(key.def_id, cause.span);
let prev = self.inner.borrow_mut().opaque_types().register(
key,
OpaqueHiddenType { ty: hidden_ty, span: cause.span },
origin,
);
match prev {
Some(prev) => self.at(cause, param_env).eq(prev, hidden_ty),
None => Ok(InferOk { value: (), obligations: vec![] }),
}
}
} }
/// Given the map `opaque_types` containing the opaque /// Given the map `opaque_types` containing the opaque
@ -324,23 +231,51 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// but this is not necessary, because the opaque type we /// but this is not necessary, because the opaque type we
/// create will be allowed to reference `T`. So we only generate a /// create will be allowed to reference `T`. So we only generate a
/// constraint that `'0: 'a`. /// constraint that `'0: 'a`.
///
/// # The `free_region_relations` parameter
///
/// The `free_region_relations` argument is used to find the
/// "minimum" of the regions supplied to a given opaque type.
/// It must be a relation that can answer whether `'a <= 'b`,
/// where `'a` and `'b` are regions that appear in the "substs"
/// for the opaque type references (the `<'a>` in `Foo1<'a>`).
///
/// Note that we do not impose the constraints based on the
/// generic regions from the `Foo1` definition (e.g., `'x`). This
/// is because the constraints we are imposing here is basically
/// the concern of the one generating the constraining type C1,
/// which is the current function. It also means that we can
/// take "implied bounds" into account in some cases:
///
/// ```text
/// trait SomeTrait<'a, 'b> { }
/// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
/// ```
///
/// Here, the fact that `'b: 'a` is known only because of the
/// implied bounds from the `&'a &'b u32` parameter, and is not
/// "inherent" to the opaque type definition.
///
/// # Parameters
///
/// - `opaque_types` -- the map produced by `instantiate_opaque_types`
/// - `free_region_relations` -- something that can be used to relate
/// the free regions (`'a`) that appear in the impl trait.
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
pub fn register_member_constraints( pub fn constrain_opaque_type(
&self, &self,
param_env: ty::ParamEnv<'tcx>,
opaque_type_key: OpaqueTypeKey<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>,
concrete_ty: Ty<'tcx>, opaque_defn: &OpaqueTypeDecl<'tcx>,
span: Span,
) { ) {
let def_id = opaque_type_key.def_id; let def_id = opaque_type_key.def_id;
let tcx = self.tcx; let tcx = self.tcx;
let concrete_ty = self.resolve_vars_if_possible(concrete_ty); let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
debug!(?concrete_ty); debug!(?concrete_ty);
let first_own_region = match self.opaque_ty_origin_unchecked(def_id, span) { let first_own_region = match opaque_defn.origin {
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => { hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
// We lower // We lower
// //
@ -384,7 +319,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
op: |r| { op: |r| {
self.member_constraint( self.member_constraint(
opaque_type_key.def_id, opaque_type_key.def_id,
span, opaque_defn.definition_span,
concrete_ty, concrete_ty,
r, r,
&choice_regions, &choice_regions,
@ -393,34 +328,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}); });
} }
pub fn opaque_ty_obligation( fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<hir::OpaqueTyOrigin> {
&self, let tcx = self.tcx;
a: Ty<'tcx>, let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
b: Ty<'tcx>,
a_is_expected: bool,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
) -> PredicateObligation<'tcx> {
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
PredicateObligation::new(
cause,
param_env,
self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::OpaqueType(a, b))),
)
}
#[instrument(skip(self), level = "trace")]
pub fn opaque_type_origin(&self, opaque_def_id: DefId, span: Span) -> Option<OpaqueTyOrigin> {
let def_id = opaque_def_id.as_local()?;
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = self.defining_use_anchor?; let parent_def_id = self.defining_use_anchor?;
let item_kind = &self.tcx.hir().expect_item(def_id).kind; let item_kind = &tcx.hir().expect_item(def_id).kind;
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else { let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
span_bug!( span_bug!(
span, tcx.def_span(def_id),
"weird opaque type: {:#?}, {:#?}", "weird opaque type: {:#?}",
opaque_def_id,
item_kind item_kind
) )
}; };
@ -431,29 +347,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id, hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
// Named `type Foo = impl Bar;` // Named `type Foo = impl Bar;`
hir::OpaqueTyOrigin::TyAlias => { hir::OpaqueTyOrigin::TyAlias => {
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id) may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
} }
}; };
trace!(?origin);
in_definition_scope.then_some(*origin) in_definition_scope.then_some(*origin)
} }
#[instrument(skip(self), level = "trace")]
fn opaque_ty_origin_unchecked(&self, opaque_def_id: DefId, span: Span) -> OpaqueTyOrigin {
let def_id = opaque_def_id.as_local().unwrap();
let origin = match self.tcx.hir().expect_item(def_id).kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
ref itemkind => {
span_bug!(span, "weird opaque type: {:?}, {:#?}", opaque_def_id, itemkind)
}
};
trace!(?origin);
origin
}
pub fn opaque_types(&self) -> OpaqueTypeMap<'tcx> {
self.inner.borrow().opaque_type_storage.opaque_types()
}
} }
// Visitor that requires that (almost) all regions in the type visited outlive // Visitor that requires that (almost) all regions in the type visited outlive
@ -528,93 +426,180 @@ where
} }
} }
pub enum UseKind { struct Instantiator<'a, 'tcx> {
DefiningUse, infcx: &'a InferCtxt<'a, 'tcx>,
OpaqueUse, body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value_span: Span,
obligations: Vec<traits::PredicateObligation<'tcx>>,
} }
impl UseKind { impl<'a, 'tcx> Instantiator<'a, 'tcx> {
pub fn is_defining(self) -> bool { fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
match self { let tcx = self.infcx.tcx;
UseKind::DefiningUse => true, value.fold_with(&mut BottomUpFolder {
UseKind::OpaqueUse => false, tcx,
} ty_op: |ty| {
if ty.references_error() {
return tcx.ty_error();
} else if let ty::Opaque(def_id, substs) = ty.kind() {
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
// value we are inferring. At present, this is
// always true during the first phase of
// type-check, but not always true later on during
// NLL. Once we support named opaque types more fully,
// this same scenario will be able to arise during all phases.
//
// Here is an example using type alias `impl Trait`
// that indicates the distinction we are checking for:
//
// ```rust
// mod a {
// pub type Foo = impl Iterator;
// pub fn make_foo() -> Foo { .. }
// }
//
// mod b {
// fn foo() -> a::Foo { a::make_foo() }
// }
// ```
//
// Here, the return type of `foo` references an
// `Opaque` indeed, but not one whose value is
// presently being inferred. You can get into a
// similar situation with closure return types
// today:
//
// ```rust
// fn foo() -> impl Iterator { .. }
// fn bar() {
// let x = || foo(); // returns the Opaque assoc with `foo`
// }
// ```
if let Some(def_id) = def_id.as_local() {
if let Some(origin) = self.infcx.opaque_type_origin(def_id) {
let opaque_type_key =
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
return self.fold_opaque_ty(ty, opaque_type_key, origin);
}
debug!(
"instantiate_opaque_types_in_map: \
encountered opaque outside its definition scope \
def_id={:?}",
def_id,
);
}
}
ty
},
lt_op: |lt| lt,
ct_op: |ct| ct,
})
} }
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn register_hidden_type( fn fold_opaque_ty(
&self, &mut self,
ty: Ty<'tcx>,
opaque_type_key: OpaqueTypeKey<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
origin: hir::OpaqueTyOrigin, origin: hir::OpaqueTyOrigin,
) -> InferResult<'tcx, ()> { ) -> Ty<'tcx> {
let tcx = self.tcx; let infcx = self.infcx;
let tcx = infcx.tcx;
let OpaqueTypeKey { def_id, substs } = opaque_type_key; let OpaqueTypeKey { def_id, substs } = opaque_type_key;
// Use the same type variable if the exact same opaque type appears more
// than once in the return type (e.g., if it's passed to a type alias).
if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
return opaque_defn.concrete_ty;
}
let ty_var = infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span: self.value_span,
});
// Ideally, we'd get the span where *this specific `ty` came // Ideally, we'd get the span where *this specific `ty` came
// from*, but right now we just use the span from the overall // from*, but right now we just use the span from the overall
// value being folded. In simple cases like `-> impl Foo`, // value being folded. In simple cases like `-> impl Foo`,
// these are the same span, but not in cases like `-> (impl // these are the same span, but not in cases like `-> (impl
// Foo, impl Bar)`. // Foo, impl Bar)`.
let span = cause.span; let definition_span = self.value_span;
let mut obligations = vec![]; {
let prev = self.inner.borrow_mut().opaque_types().register( let mut infcx = self.infcx.inner.borrow_mut();
OpaqueTypeKey { def_id, substs }, infcx.opaque_types.insert(
OpaqueHiddenType { ty: hidden_ty, span }, OpaqueTypeKey { def_id, substs },
origin, OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
); );
if let Some(prev) = prev { infcx.opaque_types_vars.insert(ty_var, ty);
obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations;
} }
debug!("generated new type inference var {:?}", ty_var.kind());
let item_bounds = tcx.explicit_item_bounds(def_id); let item_bounds = tcx.explicit_item_bounds(def_id);
self.obligations.reserve(item_bounds.len());
for (predicate, _) in item_bounds { for (predicate, _) in item_bounds {
debug!(?predicate); debug!(?predicate);
let predicate = predicate.subst(tcx, substs); let predicate = predicate.subst(tcx, substs);
debug!(?predicate);
let predicate = predicate.fold_with(&mut BottomUpFolder { let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx, tcx,
ty_op: |ty| match *ty.kind() { ty_op: |ty| match *ty.kind() {
// We can't normalize associated types from `rustc_infer`,
// but we can eagerly register inference variables for them.
ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
self.infer_projection(
param_env,
projection_ty,
cause.clone(),
0,
&mut obligations,
)
}
// Replace all other mentions of the same opaque type with the hidden type, // Replace all other mentions of the same opaque type with the hidden type,
// as the bounds must hold on the hidden type after all. // as the bounds must hold on the hidden type after all.
ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => { ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => {
hidden_ty ty_var
} }
// Instantiate nested instances of `impl Trait`.
ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty),
_ => ty, _ => ty,
}, },
lt_op: |lt| lt, lt_op: |lt| lt,
ct_op: |ct| ct, ct_op: |ct| ct,
}); });
// We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| match ty.kind() {
ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
infcx.infer_projection(
self.param_env,
*projection_ty,
traits::ObligationCause::misc(self.value_span, self.body_id),
0,
&mut self.obligations,
)
}
_ => ty,
},
lt_op: |lt| lt,
ct_op: |ct| ct,
});
debug!(?predicate);
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() { if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
if projection.term.references_error() { if projection.term.references_error() {
// No point on adding these obligations since there's a type error involved. return tcx.ty_error();
return Ok(InferOk { value: (), obligations: vec![] });
} }
trace!("{:#?}", projection.term);
} }
let cause =
traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
// Require that the predicate holds for the concrete type. // Require that the predicate holds for the concrete type.
debug!(?predicate); debug!(?predicate);
obligations.push(traits::Obligation::new(cause.clone(), param_env, predicate)); self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
} }
Ok(InferOk { value: (), obligations })
ty_var
} }
} }

View File

@ -1,88 +0,0 @@
use rustc_data_structures::undo_log::UndoLogs;
use rustc_hir::OpaqueTyOrigin;
use rustc_middle::ty::{self, OpaqueTypeKey, Ty};
use rustc_span::DUMMY_SP;
use crate::infer::{InferCtxtUndoLogs, UndoLog};
use super::{OpaqueHiddenType, OpaqueTypeDecl, OpaqueTypeMap};
#[derive(Default, Debug)]
pub struct OpaqueTypeStorage<'tcx> {
// Opaque types found in explicit return types and their
// associated fresh inference variable. Writeback resolves these
// variables to get the concrete type, which can be used to
// 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
pub opaque_types: OpaqueTypeMap<'tcx>,
}
impl<'tcx> OpaqueTypeStorage<'tcx> {
#[instrument(level = "debug")]
pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>, idx: Option<OpaqueHiddenType<'tcx>>) {
if let Some(idx) = idx {
self.opaque_types.get_mut(&key).unwrap().hidden_type = idx;
} else {
match self.opaque_types.remove(&key) {
None => bug!("reverted opaque type inference that was never registered: {:?}", key),
Some(_) => {}
}
}
}
pub fn get_decl(&self, key: &OpaqueTypeKey<'tcx>) -> Option<&OpaqueTypeDecl<'tcx>> {
self.opaque_types.get(key)
}
pub fn opaque_types(&self) -> OpaqueTypeMap<'tcx> {
self.opaque_types.clone()
}
#[instrument(level = "debug")]
pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> {
std::mem::take(&mut self.opaque_types)
}
#[inline]
pub(crate) fn with_log<'a>(
&'a mut self,
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
) -> OpaqueTypeTable<'a, 'tcx> {
OpaqueTypeTable { storage: self, undo_log }
}
}
impl<'tcx> Drop for OpaqueTypeStorage<'tcx> {
fn drop(&mut self) {
if !self.opaque_types.is_empty() {
ty::tls::with(|tcx| {
tcx.sess.delay_span_bug(DUMMY_SP, &format!("{:?}", self.opaque_types))
});
}
}
}
pub struct OpaqueTypeTable<'a, 'tcx> {
storage: &'a mut OpaqueTypeStorage<'tcx>,
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
}
impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
pub fn register(
&mut self,
key: OpaqueTypeKey<'tcx>,
hidden_type: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Option<Ty<'tcx>> {
if let Some(decl) = self.storage.opaque_types.get_mut(&key) {
let prev = std::mem::replace(&mut decl.hidden_type, hidden_type);
self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev)));
return Some(prev.ty);
}
let decl = OpaqueTypeDecl { hidden_type, origin };
self.storage.opaque_types.insert(key, decl);
self.undo_log.push(UndoLog::OpaqueTypes(key, None));
None
}
}

View File

@ -28,7 +28,6 @@ pub fn explicit_outlives_bounds<'tcx>(
| ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::TypeOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None, | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
Some(OutlivesBound::RegionSubRegion(r_b, r_a)) Some(OutlivesBound::RegionSubRegion(r_b, r_a))

View File

@ -153,7 +153,6 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// This function may have to perform normalizations, and hence it /// This function may have to perform normalizations, and hence it
/// returns an `InferOk` with subobligations that must be /// returns an `InferOk` with subobligations that must be
/// processed. /// processed.
#[instrument(level = "debug", skip(self, region_bound_pairs_map))]
pub fn process_registered_region_obligations( pub fn process_registered_region_obligations(
&self, &self,
region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>, region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>,
@ -165,6 +164,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
"cannot process registered region obligations in a snapshot" "cannot process registered region obligations in a snapshot"
); );
debug!(?param_env, "process_registered_region_obligations()");
let my_region_obligations = self.take_registered_region_obligations(); let my_region_obligations = self.take_registered_region_obligations();
for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations { for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations {

View File

@ -2,7 +2,6 @@ use super::combine::{CombineFields, RelationDir};
use super::SubregionOrigin; use super::SubregionOrigin;
use crate::infer::combine::ConstEquateRelation; use crate::infer::combine::ConstEquateRelation;
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::traits::Obligation; use crate::traits::Obligation;
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
@ -75,8 +74,9 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
} }
} }
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
if a == b { if a == b {
return Ok(a); return Ok(a);
} }
@ -84,7 +84,6 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
let infcx = self.fields.infcx; let infcx = self.fields.infcx;
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
match (a.kind(), b.kind()) { match (a.kind(), b.kind()) {
(&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => { (&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
// Shouldn't have any LBR here, so we can safely put // Shouldn't have any LBR here, so we can safely put
@ -122,40 +121,6 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
Ok(self.tcx().ty_error()) Ok(self.tcx().ty_error())
} }
(&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
self.fields.infcx.super_combine_tys(self, a, b)?;
Ok(a)
}
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
if self.fields.define_opaque_types && did.is_local() =>
{
let mut generalize = |ty, ty_is_expected| {
let var = infcx.next_ty_var_id_in_universe(
TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: self.fields.trace.cause.span,
},
ty::UniverseIndex::ROOT,
);
self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
Ok(infcx.tcx.mk_ty_var(var))
};
let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
let (a, b) = match (a.kind(), b.kind()) {
(&ty::Opaque(..), _) => (a, generalize(b, true)?),
(_, &ty::Opaque(..)) => (generalize(a, false)?, b),
_ => unreachable!(),
};
self.fields.obligations.push(infcx.opaque_ty_obligation(
a,
b,
true,
self.param_env(),
self.fields.trace.cause.clone(),
));
Ok(a)
}
_ => { _ => {
self.fields.infcx.super_combine_tys(self, a, b)?; self.fields.infcx.super_combine_tys(self, a, b)?;
Ok(a) Ok(a)

View File

@ -4,15 +4,13 @@ use rustc_data_structures::snapshot_vec as sv;
use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::undo_log::{Rollback, UndoLogs};
use rustc_data_structures::unify as ut; use rustc_data_structures::unify as ut;
use rustc_middle::infer::unify_key::RegionVidKey; use rustc_middle::infer::unify_key::RegionVidKey;
use rustc_middle::ty::{self, OpaqueTypeKey}; use rustc_middle::ty;
use crate::{ use crate::{
infer::{region_constraints, type_variable, InferCtxtInner}, infer::{region_constraints, type_variable, InferCtxtInner},
traits, traits,
}; };
use super::opaque_types::OpaqueHiddenType;
pub struct Snapshot<'tcx> { pub struct Snapshot<'tcx> {
pub(crate) undo_len: usize, pub(crate) undo_len: usize,
_marker: PhantomData<&'tcx ()>, _marker: PhantomData<&'tcx ()>,
@ -20,7 +18,6 @@ pub struct Snapshot<'tcx> {
/// Records the "undo" data for a single operation that affects some form of inference variable. /// Records the "undo" data for a single operation that affects some form of inference variable.
pub(crate) enum UndoLog<'tcx> { pub(crate) enum UndoLog<'tcx> {
OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
TypeVariables(type_variable::UndoLog<'tcx>), TypeVariables(type_variable::UndoLog<'tcx>),
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>), ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
@ -67,7 +64,6 @@ impl_from! {
impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> { impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
fn reverse(&mut self, undo: UndoLog<'tcx>) { fn reverse(&mut self, undo: UndoLog<'tcx>) {
match undo { match undo {
UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx),
UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo), UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),

View File

@ -22,7 +22,6 @@
#![feature(control_flow_enum)] #![feature(control_flow_enum)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(label_break_value)] #![feature(label_break_value)]
#![feature(backtrace)]
#![recursion_limit = "512"] // For rustdoc #![recursion_limit = "512"] // For rustdoc
#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]

View File

@ -167,9 +167,6 @@ impl<'tcx> Elaborator<'tcx> {
// Currently, we do not elaborate WF predicates, // Currently, we do not elaborate WF predicates,
// although we easily could. // although we easily could.
} }
ty::PredicateKind::OpaqueType(..) => {
todo!("{:#?}", obligation)
}
ty::PredicateKind::ObjectSafe(..) => { ty::PredicateKind::ObjectSafe(..) => {
// Currently, we do not elaborate object-safe // Currently, we do not elaborate object-safe
// predicates. // predicates.

View File

@ -1654,7 +1654,6 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
Coerce(..) | Coerce(..) |
ConstEvaluatable(..) | ConstEvaluatable(..) |
ConstEquate(..) | ConstEquate(..) |
OpaqueType(..) |
TypeWellFormedFromEnv(..) => continue, TypeWellFormedFromEnv(..) => continue,
}; };
if predicate.is_global() { if predicate.is_global() {

View File

@ -178,12 +178,6 @@ pub struct QueryResponse<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>, pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: QueryRegionConstraints<'tcx>, pub region_constraints: QueryRegionConstraints<'tcx>,
pub certainty: Certainty, pub certainty: Certainty,
/// List of opaque types which we tried to compare to another type.
/// Inside the query we don't know yet whether the opaque type actually
/// should get its hidden type inferred. So we bubble the opaque type
/// and the type it was compared against upwards and let the query caller
/// handle it.
pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>,
pub value: R, pub value: R,
} }

View File

@ -53,17 +53,17 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
self.relate(a, b) self.relate(a, b)
} }
#[instrument(skip(self), level = "debug")]
fn regions( fn regions(
&mut self, &mut self,
a: ty::Region<'tcx>, a: ty::Region<'tcx>,
b: ty::Region<'tcx>, b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> { ) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
Ok(a) Ok(a)
} }
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
if a == b { if a == b {
return Ok(a); return Ok(a);
} }

View File

@ -30,7 +30,6 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal; use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorReported; use rustc_errors::ErrorReported;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
@ -465,13 +464,9 @@ pub struct TypeckResults<'tcx> {
/// this field will be set to `Some(ErrorReported)`. /// this field will be set to `Some(ErrorReported)`.
pub tainted_by_errors: Option<ErrorReported>, pub tainted_by_errors: Option<ErrorReported>,
/// All the opaque types that have hidden types set /// All the opaque types that are restricted to concrete types
/// by this function. For return-position-impl-trait we also store the /// by this function.
/// type here, so that mir-borrowck can figure out hidden types, pub concrete_opaque_types: FxHashSet<DefId>,
/// even if they are only set in dead code (which doesn't show up in MIR).
/// For type-alias-impl-trait, this map is only used to prevent query cycles,
/// so the hidden types are all `None`.
pub concrete_opaque_types: VecMap<DefId, Option<Ty<'tcx>>>,
/// Tracks the minimum captures required for a closure; /// Tracks the minimum captures required for a closure;
/// see `MinCaptureInformationMap` for more details. /// see `MinCaptureInformationMap` for more details.

View File

@ -265,10 +265,6 @@ impl FlagComputation {
ty::PredicateKind::TypeWellFormedFromEnv(ty) => { ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
self.add_ty(ty); self.add_ty(ty);
} }
ty::PredicateKind::OpaqueType(opaque, ty) => {
self.add_ty(opaque);
self.add_ty(ty);
}
} }
} }

View File

@ -1207,11 +1207,15 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
type BreakTy = FoundFlags; type BreakTy = FoundFlags;
#[inline] #[inline]
#[instrument(skip(self), level = "trace")] #[instrument(level = "trace")]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
let flags = t.flags(); debug!(
trace!(t.flags=?t.flags()); "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}",
if flags.intersects(self.flags) { t,
t.flags(),
self.flags
);
if t.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags) ControlFlow::Break(FoundFlags)
} else { } else {
ControlFlow::CONTINUE ControlFlow::CONTINUE
@ -1231,7 +1235,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
} }
#[inline] #[inline]
#[instrument(skip(self), level = "trace")] #[instrument(level = "trace")]
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = FlagComputation::for_const(c); let flags = FlagComputation::for_const(c);
trace!(r.flags=?flags); trace!(r.flags=?flags);

View File

@ -627,11 +627,6 @@ pub enum PredicateKind<'tcx> {
/// ///
/// Only used for Chalk. /// Only used for Chalk.
TypeWellFormedFromEnv(Ty<'tcx>), TypeWellFormedFromEnv(Ty<'tcx>),
/// Represents a hidden type assignment for an opaque type.
/// Such obligations get processed by checking whether the item currently being
/// type-checked may acually define it.
OpaqueType(Ty<'tcx>, Ty<'tcx>),
} }
/// The crate outlives map is computed during typeck and contains the /// The crate outlives map is computed during typeck and contains the
@ -991,7 +986,6 @@ impl<'tcx> Predicate<'tcx> {
| PredicateKind::TypeOutlives(..) | PredicateKind::TypeOutlives(..)
| PredicateKind::ConstEvaluatable(..) | PredicateKind::ConstEvaluatable(..)
| PredicateKind::ConstEquate(..) | PredicateKind::ConstEquate(..)
| PredicateKind::OpaqueType(..)
| PredicateKind::TypeWellFormedFromEnv(..) => None, | PredicateKind::TypeWellFormedFromEnv(..) => None,
} }
} }
@ -1010,7 +1004,6 @@ impl<'tcx> Predicate<'tcx> {
| PredicateKind::ClosureKind(..) | PredicateKind::ClosureKind(..)
| PredicateKind::ConstEvaluatable(..) | PredicateKind::ConstEvaluatable(..)
| PredicateKind::ConstEquate(..) | PredicateKind::ConstEquate(..)
| PredicateKind::OpaqueType(..)
| PredicateKind::TypeWellFormedFromEnv(..) => None, | PredicateKind::TypeWellFormedFromEnv(..) => None,
} }
} }
@ -1051,18 +1044,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
} }
} }
#[derive( #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, TypeFoldable)]
Copy,
Clone,
Debug,
PartialEq,
Eq,
HashStable,
TyEncodable,
TyDecodable,
TypeFoldable,
Lift
)]
pub struct OpaqueTypeKey<'tcx> { pub struct OpaqueTypeKey<'tcx> {
pub def_id: DefId, pub def_id: DefId,
pub substs: SubstsRef<'tcx>, pub substs: SubstsRef<'tcx>,

View File

@ -644,23 +644,20 @@ pub trait PrettyPrinter<'tcx>:
return Ok(self); return Ok(self);
} }
let parent = self.tcx().parent(def_id).expect("opaque types always have a parent"); return with_no_queries(|| {
match self.tcx().def_kind(parent) { let def_key = self.tcx().def_key(def_id);
DefKind::TyAlias | DefKind::AssocTy => { if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() { p!(write("{}", name));
if d == def_id { // FIXME(eddyb) print this with `print_def_path`.
// If the type alias directly starts with the `impl` of the if !substs.is_empty() {
// opaque type we're printing, then skip the `::{opaque#1}`. p!("::");
p!(print_def_path(parent, substs)); p!(generic_delimiters(|cx| cx.comma_sep(substs.iter())));
return Ok(self);
}
} }
// Complex opaque type, e.g. `type Foo = (i32, impl Debug);`
p!(print_def_path(def_id, substs));
return Ok(self); return Ok(self);
} }
_ => return self.pretty_print_opaque_impl_type(def_id, substs),
} self.pretty_print_opaque_impl_type(def_id, substs)
});
} }
ty::Str => p!("str"), ty::Str => p!("str"),
ty::Generator(did, substs, movability) => { ty::Generator(did, substs, movability) => {
@ -2610,9 +2607,6 @@ define_print_and_forward_display! {
ty::PredicateKind::TypeWellFormedFromEnv(ty) => { ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
p!("the type `", print(ty), "` is found in the environment") p!("the type `", print(ty), "` is found in the environment")
} }
ty::PredicateKind::OpaqueType(a, b) => {
p!("opaque type assigment with `", print(a), "` == `", print(b) ,"`")
}
} }
} }

View File

@ -191,9 +191,6 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
ty::PredicateKind::TypeWellFormedFromEnv(ty) => { ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
write!(f, "TypeWellFormedFromEnv({:?})", ty) write!(f, "TypeWellFormedFromEnv({:?})", ty)
} }
ty::PredicateKind::OpaqueType(a, b) => {
write!(f, "OpaqueType({:?}, {:?})", a.kind(), b.kind())
}
} }
} }
} }
@ -466,9 +463,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
ty::PredicateKind::TypeWellFormedFromEnv(ty) => { ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv) tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv)
} }
ty::PredicateKind::OpaqueType(opaque, ty) => {
Some(ty::PredicateKind::OpaqueType(tcx.lift(opaque)?, tcx.lift(ty)?))
}
} }
} }
} }

View File

@ -1866,13 +1866,6 @@ impl<'tcx> TyS<'tcx> {
} }
} }
pub fn expect_opaque_type(&self) -> ty::OpaqueTypeKey<'tcx> {
match *self.kind() {
Opaque(def_id, substs) => ty::OpaqueTypeKey { def_id, substs },
_ => bug!("`expect_opaque_type` called on non-opaque type: {}", self),
}
}
pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
match self.kind() { match self.kind() {
Adt(def, substs) => { Adt(def, substs) => {

View File

@ -1,8 +1,8 @@
use crate::build::matches::ArmHasGuard; use crate::build::matches::ArmHasGuard;
use crate::build::ForGuard::OutsideGuard; use crate::build::ForGuard::OutsideGuard;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use rustc_middle::mir::*;
use rustc_middle::thir::*; use rustc_middle::thir::*;
use rustc_middle::{mir::*, ty};
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
use rustc_session::lint::Level; use rustc_session::lint::Level;
use rustc_span::Span; use rustc_span::Span;
@ -192,9 +192,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// This return type is usually `()`, unless the block is diverging, in which case the // This return type is usually `()`, unless the block is diverging, in which case the
// return type is `!`. For the unit type, we need to actually return the unit, but in // return type is `!`. For the unit type, we need to actually return the unit, but in
// the case of `!`, no return value is required, as the block will never return. // the case of `!`, no return value is required, as the block will never return.
// Opaque types of empty bodies also need this unit assignment, in order to infer that their if destination_ty.is_unit() {
// type is actually unit. Otherwise there will be no defining use found in the MIR.
if destination_ty.is_unit() || matches!(destination_ty.kind(), ty::Opaque(..)) {
// We only want to assign an implicit `()` as the return value of the block if the // We only want to assign an implicit `()` as the return value of the block if the
// block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.) // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
this.cfg.push_assign_unit(block, source_info, destination, this.tcx); this.cfg.push_assign_unit(block, source_info, destination, this.tcx);

View File

@ -186,6 +186,7 @@ impl<K: DepKind> EncoderState<K> {
} }
} }
#[instrument(level = "debug", skip(self, record_graph))]
fn encode_node( fn encode_node(
&mut self, &mut self,
node: &NodeInfo<K>, node: &NodeInfo<K>,
@ -212,6 +213,7 @@ impl<K: DepKind> EncoderState<K> {
stat.edge_counter += edge_count as u64; stat.edge_counter += edge_count as u64;
} }
debug!(?index, ?node);
let encoder = &mut self.encoder; let encoder = &mut self.encoder;
if self.result.is_ok() { if self.result.is_ok() {
self.result = node.encode(encoder); self.result = node.encode(encoder);

View File

@ -33,7 +33,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
/// purpose of this function is to do that translation. /// purpose of this function is to do that translation.
/// ///
/// (*) C1 and C2 were introduced in the comments on /// (*) C1 and C2 were introduced in the comments on
/// `register_member_constraints`. Read that comment for more context. /// `constrain_opaque_type`. Read that comment for more context.
/// ///
/// # Parameters /// # Parameters
/// ///
@ -48,10 +48,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
instantiated_ty: Ty<'tcx>, instantiated_ty: Ty<'tcx>,
span: Span, span: Span,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
if self.is_tainted_by_errors() {
return self.tcx.ty_error();
}
let OpaqueTypeKey { def_id, substs } = opaque_type_key; let OpaqueTypeKey { def_id, substs } = opaque_type_key;
// Use substs to build up a reverse map from regions to their // Use substs to build up a reverse map from regions to their
@ -71,6 +67,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// after producing an error for each of them. // after producing an error for each of them.
let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new( let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new(
self.tcx, self.tcx,
self.is_tainted_by_errors(),
def_id, def_id,
map, map,
instantiated_ty, instantiated_ty,
@ -85,6 +82,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
struct ReverseMapper<'tcx> { struct ReverseMapper<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
/// If errors have already been reported in this fn, we suppress
/// our own errors because they are sometimes derivative.
tainted_by_errors: bool,
opaque_type_def_id: DefId, opaque_type_def_id: DefId,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
map_missing_regions_to_empty: bool, map_missing_regions_to_empty: bool,
@ -99,6 +100,7 @@ struct ReverseMapper<'tcx> {
impl<'tcx> ReverseMapper<'tcx> { impl<'tcx> ReverseMapper<'tcx> {
fn new( fn new(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
tainted_by_errors: bool,
opaque_type_def_id: DefId, opaque_type_def_id: DefId,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
hidden_ty: Ty<'tcx>, hidden_ty: Ty<'tcx>,
@ -106,6 +108,7 @@ impl<'tcx> ReverseMapper<'tcx> {
) -> Self { ) -> Self {
Self { Self {
tcx, tcx,
tainted_by_errors,
opaque_type_def_id, opaque_type_def_id,
map, map,
map_missing_regions_to_empty: false, map_missing_regions_to_empty: false,
@ -164,7 +167,9 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
match self.map.get(&r.into()).map(|k| k.unpack()) { match self.map.get(&r.into()).map(|k| k.unpack()) {
Some(GenericArgKind::Lifetime(r1)) => r1, Some(GenericArgKind::Lifetime(r1)) => r1,
Some(u) => panic!("region mapped to unexpected kind: {:?}", u), Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty, None if self.map_missing_regions_to_empty || self.tainted_by_errors => {
self.tcx.lifetimes.re_root_empty
}
None if generics.parent.is_some() => { None if generics.parent.is_some() => {
if let Some(hidden_ty) = self.hidden_ty.take() { if let Some(hidden_ty) = self.hidden_ty.take() {
unexpected_hidden_region_diagnostic( unexpected_hidden_region_diagnostic(
@ -354,7 +359,6 @@ crate fn required_region_bounds<'tcx>(
| ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None, | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => { ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
// Search for a bound of the form `erased_self_ty // Search for a bound of the form `erased_self_ty

View File

@ -853,7 +853,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
| ty::PredicateKind::Subtype(..) | ty::PredicateKind::Subtype(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::Coerce(..) | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {} | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
}; };
} }

View File

@ -90,11 +90,6 @@ pub fn codegen_fulfill_obligation<'tcx>(
}); });
let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source); let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
// We may constrain the hidden types of opaque types in this query, but this is
// not information our callers need, as all that information is handled by borrowck
// and typeck.
drop(infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types());
debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source); debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
Ok(&*tcx.arena.alloc(impl_source)) Ok(&*tcx.arena.alloc(impl_source))
}) })

View File

@ -775,10 +775,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
span, span,
"TypeWellFormedFromEnv predicate should only exist in the environment" "TypeWellFormedFromEnv predicate should only exist in the environment"
), ),
ty::PredicateKind::OpaqueType(..) => {
todo!("{:#?}", obligation);
}
} }
} }

View File

@ -1328,7 +1328,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
ty::Generator(..) => "generator", ty::Generator(..) => "generator",
_ => "function", _ => "function",
}; };
let span = self.tcx.sess.source_map().guess_head_span(span);
let mut err = struct_span_err!( let mut err = struct_span_err!(
self.tcx.sess, self.tcx.sess,
span, span,
@ -1681,7 +1680,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
)); ));
let original_span = err.span.primary_span().unwrap(); let original_span = err.span.primary_span().unwrap();
let original_span = self.tcx.sess.source_map().guess_head_span(original_span);
let mut span = MultiSpan::from_span(original_span); let mut span = MultiSpan::from_span(original_span);
let message = outer_generator let message = outer_generator

View File

@ -397,9 +397,6 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
ty::PredicateKind::TypeWellFormedFromEnv(..) => { ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk") bug!("TypeWellFormedFromEnv is only used for Chalk")
} }
ty::PredicateKind::OpaqueType(..) => {
todo!("{:#?}", obligation);
}
}, },
Some(pred) => match pred { Some(pred) => match pred {
ty::PredicateKind::Trait(data) => { ty::PredicateKind::Trait(data) => {
@ -645,20 +642,6 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
ty::PredicateKind::TypeWellFormedFromEnv(..) => { ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk") bug!("TypeWellFormedFromEnv is only used for Chalk")
} }
ty::PredicateKind::OpaqueType(a, b) => {
match self.selcx.infcx().handle_opaque_type(
a,
b,
&obligation.cause,
obligation.param_env,
) {
Ok(value) => ProcessResult::Changed(mk_pending(value.obligations)),
Err(err) => ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
ExpectedFound::new(true, a, b),
err,
)),
}
}
}, },
} }
} }

View File

@ -313,7 +313,6 @@ fn predicate_references_self<'tcx>(
| ty::PredicateKind::Coerce(..) | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None, | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
} }
} }
@ -348,7 +347,6 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
| ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::TypeOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => false, | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
} }
}) })

View File

@ -3,8 +3,7 @@ use crate::infer::{InferCtxt, InferOk};
use crate::traits::engine::TraitEngineExt as _; use crate::traits::engine::TraitEngineExt as _;
use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::type_op::TypeOpOutput;
use crate::traits::query::Fallible; use crate::traits::query::Fallible;
use crate::traits::TraitEngine; use crate::traits::{ObligationCause, TraitEngine};
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::traits::TraitEngineExt as _; use rustc_infer::traits::TraitEngineExt as _;
use rustc_span::source_map::DUMMY_SP; use rustc_span::source_map::DUMMY_SP;
@ -32,9 +31,6 @@ where
G: Fn() -> String, G: Fn() -> String,
{ {
type Output = R; 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, /// Processes the operation and all resulting obligations,
/// returning the final result along with any region constraints /// returning the final result along with any region constraints
@ -44,7 +40,7 @@ where
info!("fully_perform({:?})", self); info!("fully_perform({:?})", self);
} }
Ok(scrape_region_constraints(infcx, || (self.closure)(infcx))?.0) scrape_region_constraints(infcx, || (self.closure)(infcx))
} }
} }
@ -59,11 +55,12 @@ where
/// Executes `op` and then scrapes out all the "old style" region /// Executes `op` and then scrapes out all the "old style" region
/// constraints that result, creating query-region-constraints. /// constraints that result, creating query-region-constraints.
pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>, op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { ) -> Fallible<TypeOpOutput<'tcx, Op>> {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
let dummy_body_id = ObligationCause::dummy().body_id;
// During NLL, we expect that nobody will register region // During NLL, we expect that nobody will register region
// obligations **except** as part of a custom type op (and, at the // obligations **except** as part of a custom type op (and, at the
@ -78,6 +75,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
); );
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations); fulfill_cx.register_predicate_obligations(infcx, obligations);
let errors = fulfill_cx.select_all_or_error(infcx); let errors = fulfill_cx.select_all_or_error(infcx);
if !errors.is_empty() { if !errors.is_empty() {
@ -101,18 +99,12 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
); );
if region_constraints.is_empty() { if region_constraints.is_empty() {
Ok(( Ok(TypeOpOutput { output: value, constraints: None, canonicalized_query: None })
TypeOpOutput { output: value, constraints: None, error_info: None },
region_constraint_data,
))
} else { } else {
Ok(( Ok(TypeOpOutput {
TypeOpOutput { output: value,
output: value, constraints: Some(Rc::new(region_constraints)),
constraints: Some(Rc::new(region_constraints)), canonicalized_query: None,
error_info: None, })
},
region_constraint_data,
))
} }
} }

View File

@ -28,7 +28,6 @@ pub use rustc_middle::traits::query::type_op::*;
/// cannot be completed). /// cannot be completed).
pub trait TypeOp<'tcx>: Sized + fmt::Debug { pub trait TypeOp<'tcx>: Sized + fmt::Debug {
type Output; type Output;
type ErrorInfo;
/// Processes the operation and all resulting obligations, /// Processes the operation and all resulting obligations,
/// returning the final result along with any region constraints /// returning the final result along with any region constraints
@ -42,8 +41,9 @@ pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> {
pub output: Op::Output, pub output: Op::Output,
/// Any region constraints from performing the type op. /// Any region constraints from performing the type op.
pub constraints: Option<Rc<QueryRegionConstraints<'tcx>>>, pub constraints: Option<Rc<QueryRegionConstraints<'tcx>>>,
/// Used for error reporting to be able to rerun the query /// The canonicalized form of the query.
pub error_info: Option<Op::ErrorInfo>, /// This for error reporting to be able to rerun the query.
pub canonicalized_query: Option<Canonical<'tcx, Op>>,
} }
/// "Query type ops" are type ops that are implemented using a /// "Query type ops" are type ops that are implemented using a
@ -119,11 +119,10 @@ where
Q: QueryTypeOp<'tcx>, Q: QueryTypeOp<'tcx>,
{ {
type Output = Q::QueryResponse; type Output = Q::QueryResponse;
type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>;
fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
let mut region_constraints = QueryRegionConstraints::default(); let mut region_constraints = QueryRegionConstraints::default();
let (output, error_info, mut obligations, _) = let (output, canonicalized_query, mut obligations, _) =
Q::fully_perform_into(self, infcx, &mut region_constraints)?; Q::fully_perform_into(self, infcx, &mut region_constraints)?;
// Typically, instantiating NLL query results does not // Typically, instantiating NLL query results does not
@ -161,6 +160,6 @@ where
let region_constraints = let region_constraints =
if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) }; if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) };
Ok(TypeOpOutput { output, constraints: region_constraints, error_info }) Ok(TypeOpOutput { output, constraints: region_constraints, canonicalized_query })
} }
} }

View File

@ -254,7 +254,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}; };
if obligation.predicate.skip_binder().self_ty().is_ty_var() { if obligation.predicate.skip_binder().self_ty().is_ty_var() {
debug!(ty = ?obligation.predicate.skip_binder().self_ty(), "ambiguous inference var or opaque type");
// Self is a type variable (e.g., `_: AsRef<str>`). // Self is a type variable (e.g., `_: AsRef<str>`).
// //
// This is somewhat problematic, as the current scheme can't really // This is somewhat problematic, as the current scheme can't really

View File

@ -37,7 +37,6 @@ use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::thir::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences}; use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
@ -698,19 +697,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::PredicateKind::TypeWellFormedFromEnv(..) => { ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for chalk") bug!("TypeWellFormedFromEnv is only used for chalk")
} }
ty::PredicateKind::OpaqueType(a, b) => {
match self.infcx().handle_opaque_type(
a,
b,
&obligation.cause,
obligation.param_env,
) {
Ok(res) => {
self.evaluate_predicates_recursively(previous_stack, res.obligations)
}
Err(_) => Ok(EvaluatedToErr),
}
}
} }
}); });
@ -1351,7 +1337,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
} }
#[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")]
fn insert_candidate_cache( fn insert_candidate_cache(
&mut self, &mut self,
mut param_env: ty::ParamEnv<'tcx>, mut param_env: ty::ParamEnv<'tcx>,
@ -1392,7 +1377,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// a projection, look at the bounds of `T::Bar`, see if we can find a /// a projection, look at the bounds of `T::Bar`, see if we can find a
/// `Baz` bound. We return indexes into the list returned by /// `Baz` bound. We return indexes into the list returned by
/// `tcx.item_bounds` for any applicable bounds. /// `tcx.item_bounds` for any applicable bounds.
#[instrument(level = "debug", skip(self))]
fn match_projection_obligation_against_definition_bounds( fn match_projection_obligation_against_definition_bounds(
&mut self, &mut self,
obligation: &TraitObligation<'tcx>, obligation: &TraitObligation<'tcx>,
@ -1400,7 +1384,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate); let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
let placeholder_trait_predicate = let placeholder_trait_predicate =
self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate); self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
debug!(?placeholder_trait_predicate); debug!(
?placeholder_trait_predicate,
"match_projection_obligation_against_definition_bounds"
);
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
@ -1451,7 +1438,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}) })
.collect(); .collect();
debug!(?matching_bounds); debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds");
matching_bounds matching_bounds
} }
@ -1481,7 +1468,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}); });
self.infcx self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.define_opaque_types(false)
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
.map(|InferOk { obligations: _, value: () }| { .map(|InferOk { obligations: _, value: () }| {
// This method is called within a probe, so we can't have // This method is called within a probe, so we can't have
@ -1537,7 +1523,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.infcx self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.define_opaque_types(false)
.sup(obligation.predicate, infer_projection) .sup(obligation.predicate, infer_projection)
.map_or(false, |InferOk { obligations, value: () }| { .map_or(false, |InferOk { obligations, value: () }| {
self.evaluate_predicates_recursively( self.evaluate_predicates_recursively(
@ -2096,22 +2081,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match self.match_impl(impl_def_id, obligation) { match self.match_impl(impl_def_id, obligation) {
Ok(substs) => substs, Ok(substs) => substs,
Err(()) => { Err(()) => {
self.infcx.tcx.sess.delay_span_bug( bug!(
obligation.cause.span, "Impl {:?} was matchable against {:?} but now is not",
&format!( impl_def_id,
"Impl {:?} was matchable against {:?} but now is not", obligation
impl_def_id, obligation
),
); );
let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
let err = self.tcx().ty_error();
let value = value.fold_with(&mut BottomUpFolder {
tcx: self.tcx(),
ty_op: |_| err,
lt_op: |l| l,
ct_op: |c| c,
});
Normalized { value, obligations: vec![] }
} }
} }
} }
@ -2248,11 +2222,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<Vec<PredicateObligation<'tcx>>, ()> { ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
self.infcx self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
// We don't want predicates for opaque types to just match all other types,
// if there is an obligation on the opaque type, then that obligation must be met
// opaquely. Otherwise we'd match any obligation to the opaque type and then error
// out later.
.define_opaque_types(false)
.sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
.map(|InferOk { obligations, .. }| obligations) .map(|InferOk { obligations, .. }| obligations)
.map_err(|_| ()) .map_err(|_| ())

View File

@ -146,10 +146,6 @@ pub fn predicate_obligations<'a, 'tcx>(
wf.compute(c1.into()); wf.compute(c1.into());
wf.compute(c2.into()); wf.compute(c2.into());
} }
ty::PredicateKind::OpaqueType(opaque, ty) => {
wf.compute(opaque.into());
wf.compute(ty.into());
}
ty::PredicateKind::TypeWellFormedFromEnv(..) => { ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk") bug!("TypeWellFormedFromEnv is only used for Chalk")
} }

View File

@ -110,7 +110,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
| ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..) | ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..) | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate), | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
}; };
@ -197,7 +196,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
| ty::PredicateKind::Subtype(..) | ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..) | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::ConstEquate(..) => { | ty::PredicateKind::ConstEquate(..) => {
chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
} }
@ -612,7 +610,6 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
| ty::PredicateKind::Coerce(..) | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => { | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("unexpected predicate {}", &self) bug!("unexpected predicate {}", &self)
} }
@ -742,7 +739,6 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
| ty::PredicateKind::Coerce(..) | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => { | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("unexpected predicate {}", &self) bug!("unexpected predicate {}", &self)
} }

View File

@ -142,7 +142,6 @@ crate fn evaluate_goal<'tcx>(
var_values: CanonicalVarValues { var_values }, var_values: CanonicalVarValues { var_values },
region_constraints: QueryRegionConstraints::default(), region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Proven, certainty: Certainty::Proven,
opaque_types: vec![],
value: (), value: (),
}, },
}; };
@ -171,7 +170,6 @@ crate fn evaluate_goal<'tcx>(
.make_identity(tcx), .make_identity(tcx),
region_constraints: QueryRegionConstraints::default(), region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Ambiguous, certainty: Certainty::Ambiguous,
opaque_types: vec![],
value: (), value: (),
}, },
}; };

View File

@ -105,7 +105,6 @@ fn compute_implied_outlives_bounds<'tcx>(
| ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![], | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![],
ty::PredicateKind::WellFormed(arg) => { ty::PredicateKind::WellFormed(arg) => {
wf_args.push(arg); wf_args.push(arg);

View File

@ -69,7 +69,6 @@ fn not_outlives_predicate<'tcx>(p: &ty::Predicate<'tcx>) -> bool {
| ty::PredicateKind::Coerce(..) | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => true, | ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
} }
} }

View File

@ -61,14 +61,6 @@ bitflags! {
| TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_CT_INFER.bits
| TypeFlags::HAS_TY_PLACEHOLDER.bits | TypeFlags::HAS_TY_PLACEHOLDER.bits
| TypeFlags::HAS_CT_PLACEHOLDER.bits | TypeFlags::HAS_CT_PLACEHOLDER.bits
// The `evaluate_obligation` query does not return further
// obligations. If it evaluates an obligation with an opaque
// type, that opaque type may get compared to another type,
// constraining it. We would lose this information.
// FIXME: differentiate between crate-local opaque types
// and opaque types from other crates, as only opaque types
// from the local crate can possibly be a local name
| TypeFlags::HAS_TY_OPAQUE.bits
// We consider 'freshened' types and constants // We consider 'freshened' types and constants
// to depend on a particular fn. // to depend on a particular fn.
// The freshening process throws away information, // The freshening process throws away information,

View File

@ -4,7 +4,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir::{self as hir, ExprKind}; use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::Obligation; use rustc_infer::traits::Obligation;
use rustc_middle::ty::{self, ToPredicate, Ty, TyS, TypeFoldable}; use rustc_middle::ty::{self, ToPredicate, Ty, TyS};
use rustc_span::{MultiSpan, Span}; use rustc_span::{MultiSpan, Span};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{ use rustc_trait_selection::traits::{
@ -98,7 +98,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let arm_ty = self.check_expr_with_expectation(&arm.body, expected); let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
all_arms_diverge &= self.diverges.get(); all_arms_diverge &= self.diverges.get();
let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected); let opt_suggest_box_span =
self.opt_suggest_box_span(arm.body.span, arm_ty, orig_expected);
let (arm_span, semi_span) = let (arm_span, semi_span) =
self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty); self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
@ -503,15 +504,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// provide a structured suggestion in that case. // provide a structured suggestion in that case.
pub(crate) fn opt_suggest_box_span( pub(crate) fn opt_suggest_box_span(
&self, &self,
span: Span,
outer_ty: &'tcx TyS<'tcx>, outer_ty: &'tcx TyS<'tcx>,
orig_expected: Expectation<'tcx>, orig_expected: Expectation<'tcx>,
) -> Option<Span> { ) -> Option<Span> {
match orig_expected { match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) {
Expectation::ExpectHasType(expected) (Expectation::ExpectHasType(expected), Some((_id, ty)))
if self.in_tail_expr if self.in_tail_expr && self.can_coerce(outer_ty, expected) =>
&& self.ret_coercion.as_ref()?.borrow().merged_ty().has_opaque_types()
&& self.can_coerce(outer_ty, expected) =>
{ {
let impl_trait_ret_ty =
self.infcx.instantiate_opaque_types(self.body_id, self.param_env, ty, span);
assert!(
impl_trait_ret_ty.obligations.is_empty(),
"we should never get new obligations here"
);
let obligations = self.fulfillment_cx.borrow().pending_obligations(); let obligations = self.fulfillment_cx.borrow().pending_obligations();
let mut suggest_box = !obligations.is_empty(); let mut suggest_box = !obligations.is_empty();
for o in obligations { for o in obligations {

View File

@ -545,7 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Expectation<'tcx>, expected: Expectation<'tcx>,
fn_sig: ty::FnSig<'tcx>, fn_sig: ty::FnSig<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
// `fn_sig` is the *signature* of the closure being called. We // `fn_sig` is the *signature* of the cosure being called. We
// don't know the full details yet (`Fn` vs `FnMut` etc), but we // don't know the full details yet (`Fn` vs `FnMut` etc), but we
// do know the types expected for each argument and the return // do know the types expected for each argument and the return
// type. // type.

View File

@ -17,7 +17,7 @@ use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::layout::MAX_SIMD_LANES; use rustc_middle::ty::layout::MAX_SIMD_LANES;
use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt}; use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, RegionKind, Ty, TyCtxt};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::{self, MultiSpan, Span}; use rustc_span::{self, MultiSpan, Span};
@ -81,6 +81,8 @@ pub(super) fn check_fn<'a, 'tcx>(
can_be_generator: Option<hir::Movability>, can_be_generator: Option<hir::Movability>,
return_type_pre_known: bool, return_type_pre_known: bool,
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) { ) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
let mut fn_sig = fn_sig;
// Create the function context. This is either derived from scratch or, // Create the function context. This is either derived from scratch or,
// in the case of closures, based on the outer context. // in the case of closures, based on the outer context.
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
@ -93,8 +95,21 @@ pub(super) fn check_fn<'a, 'tcx>(
let declared_ret_ty = fn_sig.output(); let declared_ret_ty = fn_sig.output();
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(declared_ret_ty))); let revealed_ret_ty =
fcx.instantiate_opaque_types_from_value(declared_ret_ty, decl.output.span());
debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
fcx.ret_type_span = Some(decl.output.span()); fcx.ret_type_span = Some(decl.output.span());
if let ty::Opaque(..) = declared_ret_ty.kind() {
fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
}
fn_sig = tcx.mk_fn_sig(
fn_sig.inputs().iter().cloned(),
revealed_ret_ty,
fn_sig.c_variadic,
fn_sig.unsafety,
fn_sig.abi,
);
let span = body.value.span; let span = body.value.span;
@ -236,7 +251,7 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span }); fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
debug!("actual_return_ty replaced with {:?}", actual_return_ty); debug!("actual_return_ty replaced with {:?}", actual_return_ty);
} }
fcx.demand_suptype(span, declared_ret_ty, actual_return_ty); fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
@ -614,8 +629,6 @@ fn check_opaque_meets_bounds<'tcx>(
span: Span, span: Span,
origin: &hir::OpaqueTyOrigin, origin: &hir::OpaqueTyOrigin,
) { ) {
let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let defining_use_anchor = match *origin { let defining_use_anchor = match *origin {
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
@ -630,12 +643,24 @@ fn check_opaque_meets_bounds<'tcx>(
let misc_cause = traits::ObligationCause::misc(span, hir_id); let misc_cause = traits::ObligationCause::misc(span, hir_id);
match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) { let _ = inh.register_infer_ok_obligations(
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok), infcx.instantiate_opaque_types(hir_id, param_env, opaque_ty, span),
Err(ty_err) => tcx.sess.delay_span_bug( );
span,
&format!("could not unify `{}` with revealed type:\n{}", hidden_type, ty_err,), let opaque_type_map = infcx.inner.borrow().opaque_types.clone();
), for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
trace!(?hidden_type);
match infcx.at(&misc_cause, param_env).eq(opaque_defn.concrete_ty, hidden_type) {
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
Err(ty_err) => tcx.sess.delay_span_bug(
span,
&format!(
"could not check bounds on revealed type `{}`:\n{}",
hidden_type, ty_err,
),
),
}
} }
// Check that all obligations are satisfied by the implementation's // Check that all obligations are satisfied by the implementation's
@ -647,7 +672,7 @@ fn check_opaque_meets_bounds<'tcx>(
match origin { match origin {
// Checked when type checking the function containing them. // Checked when type checking the function containing them.
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
// Can have different predicates to their defining use // Can have different predicates to their defining use
hir::OpaqueTyOrigin::TyAlias => { hir::OpaqueTyOrigin::TyAlias => {
// Finally, resolve all regions. This catches wily misuses of // Finally, resolve all regions. This catches wily misuses of
@ -656,9 +681,6 @@ fn check_opaque_meets_bounds<'tcx>(
fcx.regionck_item(hir_id, span, FxHashSet::default()); fcx.regionck_item(hir_id, span, FxHashSet::default());
} }
} }
// Clean up after ourselves
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
}); });
} }

View File

@ -3,20 +3,16 @@
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
use crate::astconv::AstConv; use crate::astconv::AstConv;
use crate::rustc_middle::ty::subst::Subst;
use hir::OpaqueTyOrigin;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult}; use rustc_infer::infer::{InferOk, InferResult};
use rustc_infer::traits::ObligationCause;
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_span::DUMMY_SP;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::ArgKind; use rustc_trait_selection::traits::error_reporting::ArgKind;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
@ -176,29 +172,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty: Ty<'tcx>, expected_ty: Ty<'tcx>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) { ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
match *expected_ty.kind() { match *expected_ty.kind() {
ty::Opaque(def_id, substs) => {
let bounds = self.tcx.explicit_item_bounds(def_id);
let sig = bounds.iter().find_map(|(pred, span)| match pred.kind().skip_binder() {
ty::PredicateKind::Projection(proj_predicate) => self
.deduce_sig_from_projection(
Some(*span),
pred.kind().rebind(proj_predicate.subst(self.tcx, substs)),
),
_ => None,
});
let kind = bounds
.iter()
.filter_map(|(pred, _)| match pred.kind().skip_binder() {
ty::PredicateKind::Trait(tp) => {
self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
}
_ => None,
})
.fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
trace!(?sig, ?kind);
(sig, kind)
}
ty::Dynamic(ref object_type, ..) => { ty::Dynamic(ref object_type, ..) => {
let sig = object_type.projection_bounds().find_map(|pb| { let sig = object_type.projection_bounds().find_map(|pb| {
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
@ -224,7 +197,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) { ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
let expected_sig = let expected_sig =
self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| { self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
debug!(?obligation.predicate); debug!(
"deduce_expectations_from_obligations: obligation.predicate={:?}",
obligation.predicate
);
let bound_predicate = obligation.predicate.kind(); let bound_predicate = obligation.predicate.kind();
if let ty::PredicateKind::Projection(proj_predicate) = if let ty::PredicateKind::Projection(proj_predicate) =
@ -259,7 +235,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// The `cause_span` should be the span that caused us to /// The `cause_span` should be the span that caused us to
/// have this expected signature, or `None` if we can't readily /// have this expected signature, or `None` if we can't readily
/// know that. /// know that.
#[instrument(level = "debug", skip(self, cause_span))]
fn deduce_sig_from_projection( fn deduce_sig_from_projection(
&self, &self,
cause_span: Option<Span>, cause_span: Option<Span>,
@ -267,13 +242,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Option<ExpectedSig<'tcx>> { ) -> Option<ExpectedSig<'tcx>> {
let tcx = self.tcx; let tcx = self.tcx;
debug!("deduce_sig_from_projection({:?})", projection);
let trait_def_id = projection.trait_def_id(tcx); let trait_def_id = projection.trait_def_id(tcx);
let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some(); let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span); let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
let is_gen = gen_trait == trait_def_id; let is_gen = gen_trait == trait_def_id;
if !is_fn && !is_gen { if !is_fn && !is_gen {
debug!("not fn or generator"); debug!("deduce_sig_from_projection: not fn or generator");
return None; return None;
} }
@ -282,7 +259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// associated item and not yield. // associated item and not yield.
let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1]; let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1];
if return_assoc_item != projection.projection_def_id() { if return_assoc_item != projection.projection_def_id() {
debug!("not return assoc item of generator"); debug!("deduce_sig_from_projection: not return assoc item of generator");
return None; return None;
} }
} }
@ -290,7 +267,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let input_tys = if is_fn { let input_tys = if is_fn {
let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1); let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty); let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
debug!(?arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
match arg_param_ty.kind() { match arg_param_ty.kind() {
ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::<Vec<_>>(), ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::<Vec<_>>(),
@ -305,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Since this is a return parameter type it is safe to unwrap. // Since this is a return parameter type it is safe to unwrap.
let ret_param_ty = projection.skip_binder().term.ty().unwrap(); let ret_param_ty = projection.skip_binder().term.ty().unwrap();
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty); let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
debug!(?ret_param_ty); debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
let sig = projection.rebind(self.tcx.mk_fn_sig( let sig = projection.rebind(self.tcx.mk_fn_sig(
input_tys.iter(), input_tys.iter(),
@ -314,7 +291,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::Unsafety::Normal, hir::Unsafety::Normal,
Abi::Rust, Abi::Rust,
)); ));
debug!(?sig); debug!("deduce_sig_from_projection: sig={:?}", sig);
Some(ExpectedSig { cause_span, sig }) Some(ExpectedSig { cause_span, sig })
} }
@ -424,14 +401,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// in this binder we are creating. // in this binder we are creating.
assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST)); assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST));
let bound_sig = expected_sig.sig.map_bound(|sig| { let bound_sig = expected_sig.sig.map_bound(|sig| {
let output = self.hide_parent_opaque_types(
sig.output(),
expected_sig.cause_span.unwrap_or(DUMMY_SP),
body.id().hir_id,
);
self.tcx.mk_fn_sig( self.tcx.mk_fn_sig(
sig.inputs().iter().cloned(), sig.inputs().iter().cloned(),
output, sig.output(),
sig.c_variadic, sig.c_variadic,
hir::Unsafety::Normal, hir::Unsafety::Normal,
Abi::RustCall, Abi::RustCall,
@ -618,8 +590,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => astconv.ty_infer(None, decl.output.span()), _ => astconv.ty_infer(None, decl.output.span()),
}, },
}; };
let supplied_return =
self.hide_parent_opaque_types(supplied_return, decl.output.span(), body.id().hir_id);
let result = ty::Binder::bind_with_vars( let result = ty::Binder::bind_with_vars(
self.tcx.mk_fn_sig( self.tcx.mk_fn_sig(
@ -640,57 +610,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
result result
} }
fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
ty.fold_with(&mut ty::fold::BottomUpFolder {
tcx: self.infcx.tcx,
lt_op: |lt| lt,
ct_op: |ct| ct,
ty_op: |ty| match *ty.kind() {
// Closures can't create hidden types for opaque types of their parent, as they
// do not have all the outlives information available. Also `type_of` looks for
// hidden types in the owner (so the closure's parent), so it would not find these
// definitions.
ty::Opaque(def_id, _substs)
if matches!(
self.infcx.opaque_type_origin(def_id, DUMMY_SP),
Some(OpaqueTyOrigin::FnReturn(..))
) =>
{
let ty_var = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span,
});
let cause = ObligationCause::misc(span, body_id);
self.register_predicates(vec![self.infcx.opaque_ty_obligation(
ty,
ty_var,
true,
self.param_env,
cause,
)]);
ty_var
}
_ => ty,
},
})
}
/// Invoked when we are translating the generator that results /// Invoked when we are translating the generator that results
/// from desugaring an `async fn`. Returns the "sugared" return /// from desugaring an `async fn`. Returns the "sugared" return
/// type of the `async fn` -- that is, the return type that the /// type of the `async fn` -- that is, the return type that the
/// user specified. The "desugared" return type is an `impl /// user specified. The "desugared" return type is an `impl
/// Future<Output = T>`, so we do this by searching through the /// Future<Output = T>`, so we do this by searching through the
/// obligations to extract the `T`. /// obligations to extract the `T`.
#[instrument(skip(self), level = "debug")]
fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty<'tcx>> { fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty<'tcx>> {
debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id);
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| { let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn") span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn")
}); });
// In practice, the return type of the surrounding function is
// always a (not yet resolved) inference variable, because it
// is the hidden type for an `impl Trait` that we are going to
// be inferring.
let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = ret_coercion.borrow().expected_ty();
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
let (def_id, substs) = match *ret_ty.kind() { let ret_vid = match *ret_ty.kind() {
ty::Opaque(def_id, substs) => (def_id, substs), ty::Infer(ty::TyVar(ret_vid)) => ret_vid,
ty::Error(_) => return None, ty::Error(_) => return None,
_ => span_bug!( _ => span_bug!(
self.tcx.def_span(expr_def_id), self.tcx.def_span(expr_def_id),
@ -698,19 +638,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
), ),
}; };
let item_bounds = self.tcx.explicit_item_bounds(def_id);
// Search for a pending obligation like // Search for a pending obligation like
// //
// `<R as Future>::Output = T` // `<R as Future>::Output = T`
// //
// where R is the return type we are expecting. This type `T` // where R is the return type we are expecting. This type `T`
// will be our output. // will be our output.
let output_ty = item_bounds.iter().find_map(|&(predicate, span)| { let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
let bound_predicate = predicate.subst(self.tcx, substs).kind(); let bound_predicate = obligation.predicate.kind();
if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() { if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
self.deduce_future_output_from_projection( self.deduce_future_output_from_projection(
span, obligation.cause.span,
bound_predicate.rebind(proj_predicate), bound_predicate.rebind(proj_predicate),
) )
} else { } else {

View File

@ -1275,7 +1275,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
/// Returns the current "merged type", representing our best-guess /// Returns the current "merged type", representing our best-guess
/// at the LUB of the expressions we've seen so far (if any). This /// at the LUB of the expressions we've seen so far (if any). This
/// isn't *final* until you call `self.complete()`, which will return /// isn't *final* until you call `self.final()`, which will return
/// the merged type. /// the merged type.
pub fn merged_ty(&self) -> Ty<'tcx> { pub fn merged_ty(&self) -> Ty<'tcx> {
self.final_ty.unwrap_or(self.expected_ty) self.final_ty.unwrap_or(self.expected_ty)

View File

@ -1,6 +1,5 @@
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_span::DUMMY_SP;
use rustc_span::{self, Span}; use rustc_span::{self, Span};
use super::Expectation::*; use super::Expectation::*;
@ -44,7 +43,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
// when checking the 'then' block which are incompatible with the // when checking the 'then' block which are incompatible with the
// 'else' branch. // 'else' branch.
pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
match self.strip_opaque(fcx) { match *self {
ExpectHasType(ety) => { ExpectHasType(ety) => {
let ety = fcx.shallow_resolve(ety); let ety = fcx.shallow_resolve(ety);
if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
@ -105,35 +104,14 @@ impl<'a, 'tcx> Expectation<'tcx> {
/// for the program to type-check). `only_has_type` will return /// for the program to type-check). `only_has_type` will return
/// such a constraint, if it exists. /// such a constraint, if it exists.
pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> { pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
match self.strip_opaque(fcx) { match self {
ExpectHasType(ty) => Some(ty), ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)),
NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => { NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => {
None None
} }
} }
} }
/// We must not treat opaque types as expected types in their defining scope, as that
/// will break `fn foo() -> impl Trait { if cond { a } else { b } }` if `a` and `b` are
/// only "equal" if they coerce to a common target, like two different function items
/// coercing to a function pointer if they have the same signature.
fn strip_opaque(self, fcx: &FnCtxt<'a, 'tcx>) -> Self {
match self {
ExpectHasType(ty) => {
let ty = fcx.resolve_vars_if_possible(ty);
match *ty.kind() {
ty::Opaque(def_id, _)
if fcx.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() =>
{
NoExpectation
}
_ => self,
}
}
_ => self,
}
}
/// Like `only_has_type`, but instead of returning `None` if no /// Like `only_has_type`, but instead of returning `None` if no
/// hard constraint exists, creates a fresh type variable. /// hard constraint exists, creates a fresh type variable.
pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> { pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {

View File

@ -956,7 +956,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
let else_diverges = self.diverges.get(); let else_diverges = self.diverges.get();
let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected); let opt_suggest_box_span =
self.opt_suggest_box_span(else_expr.span, else_ty, orig_expected);
let if_cause = let if_cause =
self.if_cause(sp, then_expr, else_expr, then_ty, else_ty, opt_suggest_box_span); self.if_cause(sp, then_expr, else_expr, then_ty, else_ty, opt_suggest_box_span);

View File

@ -24,7 +24,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
self.fulfillment_cx.borrow_mut().pending_obligations() self.fulfillment_cx.borrow_mut().pending_obligations()
); );
// Check if we have any unsolved variables. If not, no need for fallback. // Check if we have any unsolved varibales. If not, no need for fallback.
let unsolved_variables = self.unsolved_variables(); let unsolved_variables = self.unsolved_variables();
if unsolved_variables.is_empty() { if unsolved_variables.is_empty() {
return false; return false;
@ -66,6 +66,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
// refer to opaque types. // refer to opaque types.
self.select_obligations_where_possible(fallback_has_occurred, |_| {}); self.select_obligations_where_possible(fallback_has_occurred, |_| {});
// We now run fallback again, but this time we allow it to replace
// unconstrained opaque type variables, in addition to performing
// other kinds of fallback.
for ty in &self.unsolved_variables() {
fallback_has_occurred |= self.fallback_opaque_type_vars(ty);
}
// See if we can make any more progress.
self.select_obligations_where_possible(fallback_has_occurred, |_| {});
fallback_has_occurred fallback_has_occurred
} }
@ -126,6 +136,59 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
true true
} }
/// Second round of fallback: Unconstrained type variables created
/// from the instantiation of an opaque type fall back to the
/// opaque type itself. This is a somewhat incomplete attempt to
/// manage "identity passthrough" for `impl Trait` types.
///
/// For example, in this code:
///
///```
/// type MyType = impl Copy;
/// fn defining_use() -> MyType { true }
/// fn other_use() -> MyType { defining_use() }
/// ```
///
/// `defining_use` will constrain the instantiated inference
/// variable to `bool`, while `other_use` will constrain
/// the instantiated inference variable to `MyType`.
///
/// When we process opaque types during writeback, we
/// will handle cases like `other_use`, and not count
/// them as defining usages
///
/// However, we also need to handle cases like this:
///
/// ```rust
/// pub type Foo = impl Copy;
/// fn produce() -> Option<Foo> {
/// None
/// }
/// ```
///
/// In the above snippet, the inference variable created by
/// instantiating `Option<Foo>` will be completely unconstrained.
/// We treat this as a non-defining use by making the inference
/// variable fall back to the opaque type itself.
fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool {
let span = self
.infcx
.type_var_origin(ty)
.map(|origin| origin.span)
.unwrap_or(rustc_span::DUMMY_SP);
let oty = self.inner.borrow().opaque_types_vars.get(ty).copied();
if let Some(opaque_ty) = oty {
debug!(
"fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
ty, opaque_ty
);
self.demand_eqtype(span, ty, opaque_ty);
true
} else {
return false;
}
}
/// The "diverging fallback" system is rather complicated. This is /// The "diverging fallback" system is rather complicated. This is
/// a result of our need to balance 'do the right thing' with /// a result of our need to balance 'do the right thing' with
/// backwards compatibility. /// backwards compatibility.

View File

@ -367,6 +367,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(result, spans) (result, spans)
} }
/// Replaces the opaque types from the given value with type variables,
/// and records the `OpaqueTypeMap` for later use during writeback. See
/// `InferCtxt::instantiate_opaque_types` for more details.
#[instrument(skip(self, value_span), level = "debug")]
pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
&self,
value: T,
value_span: Span,
) -> T {
self.register_infer_ok_obligations(self.instantiate_opaque_types(
self.body_id,
self.param_env,
value,
value_span,
))
}
/// Convenience method which tracks extra diagnostic information for normalization /// Convenience method which tracks extra diagnostic information for normalization
/// that occurs as a result of WF checking. The `hir_id` is the `HirId` of the hir item /// that occurs as a result of WF checking. The `hir_id` is the `HirId` of the hir item
/// whose type is being wf-checked - this is used to construct a more precise span if /// whose type is being wf-checked - this is used to construct a more precise span if
@ -703,7 +720,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// inference variable. // inference variable.
ty::PredicateKind::ClosureKind(..) => None, ty::PredicateKind::ClosureKind(..) => None,
ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::PredicateKind::OpaqueType(..) => None,
} }
}) })
.filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
@ -730,32 +746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Vec<Ty<'tcx>> { ) -> Vec<Ty<'tcx>> {
let formal_ret = self.resolve_vars_with_obligations(formal_ret); let formal_ret = self.resolve_vars_with_obligations(formal_ret);
let ret_ty = match expected_ret.only_has_type(self) { let ret_ty = match expected_ret.only_has_type(self) {
Some(ret) => { Some(ret) => ret,
// HACK(oli-obk): This is a backwards compatibility hack. Without it, the inference
// variable will get instantiated with the opaque type. The inference variable often
// has various helpful obligations registered for it that help closures figure out their
// signature. If we infer the inference var to the opaque type, the closure won't be able
// to find those obligations anymore, and it can't necessarily find them from the opaque
// type itself. We could be more powerful with inference if we *combined* the obligations
// so that we got both the obligations from the opaque type and the ones from the inference
// variable. That will accept more code than we do right now, so we need to carefully consider
// the implications.
// Note: this check is pessimistic, as the inference type could be matched with something other
// than the opaque type, but then we need a new `TypeRelation` just for this specific case and
// can't re-use `sup` below.
if formal_ret.has_infer_types() {
for ty in ret.walk() {
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() {
if let ty::Opaque(def_id, _) = *ty.kind() {
if self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() {
return Vec::new();
}
}
}
}
}
ret
}
None => return Vec::new(), None => return Vec::new(),
}; };
let expect_args = self let expect_args = self

View File

@ -57,6 +57,8 @@ pub struct FnCtxt<'a, 'tcx> {
/// any). /// any).
pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>, pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
pub(super) ret_type_span: Option<Span>, pub(super) ret_type_span: Option<Span>,
/// Used exclusively to reduce cost of advanced evaluation used for /// Used exclusively to reduce cost of advanced evaluation used for
@ -128,6 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param_env, param_env,
err_count_on_creation: inh.tcx.sess.err_count(), err_count_on_creation: inh.tcx.sess.err_count(),
ret_coercion: None, ret_coercion: None,
ret_coercion_impl_trait: None,
ret_type_span: None, ret_type_span: None,
in_tail_expr: false, in_tail_expr: false,
ret_coercion_span: Cell::new(None), ret_coercion_span: Cell::new(None),

View File

@ -95,13 +95,6 @@ impl<'tcx> InheritedBuilder<'tcx> {
let def_id = self.def_id; let def_id = self.def_id;
self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id))) self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
} }
/// WF-checking doesn't need to recompute opaque types and can instead use
/// the type_of query to get them from typeck.
pub fn reveal_defining_opaque_types(mut self) -> Self {
self.infcx = self.infcx.reveal_defining_opaque_types();
self
}
} }
impl<'a, 'tcx> Inherited<'a, 'tcx> { impl<'a, 'tcx> Inherited<'a, 'tcx> {
@ -126,8 +119,8 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
} }
} }
#[instrument(level = "debug", skip(self))]
pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
debug!("register_predicate({:?})", obligation);
if obligation.has_escaping_bound_vars() { if obligation.has_escaping_bound_vars() {
span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
} }

View File

@ -856,7 +856,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
| ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::TypeOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None, | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
} }
}); });
@ -1476,7 +1475,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
TraitCandidate(trait_ref) => self.probe(|_| { TraitCandidate(trait_ref) => self.probe(|_| {
let _ = self let _ = self
.at(&ObligationCause::dummy(), self.param_env) .at(&ObligationCause::dummy(), self.param_env)
.define_opaque_types(false)
.sup(candidate.xform_self_ty, self_ty); .sup(candidate.xform_self_ty, self_ty);
match self.select_trait_candidate(trait_ref) { match self.select_trait_candidate(trait_ref) {
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => { Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
@ -1506,7 +1504,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// First check that the self type can be related. // First check that the self type can be related.
let sub_obligations = match self let sub_obligations = match self
.at(&ObligationCause::dummy(), self.param_env) .at(&ObligationCause::dummy(), self.param_env)
.define_opaque_types(false)
.sup(probe.xform_self_ty, self_ty) .sup(probe.xform_self_ty, self_ty)
{ {
Ok(InferOk { obligations, value: () }) => obligations, Ok(InferOk { obligations, value: () }) => obligations,
@ -1654,7 +1651,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
); );
if self if self
.at(&ObligationCause::dummy(), self.param_env) .at(&ObligationCause::dummy(), self.param_env)
.define_opaque_types(false)
.sup(return_ty, xform_ret_ty) .sup(return_ty, xform_ret_ty)
.is_err() .is_err()
{ {

View File

@ -341,7 +341,6 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
typeck_with_fallback(tcx, def_id, fallback) typeck_with_fallback(tcx, def_id, fallback)
} }
#[instrument(skip(tcx, fallback))]
fn typeck_with_fallback<'tcx>( fn typeck_with_fallback<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: LocalDefId, def_id: LocalDefId,

View File

@ -335,6 +335,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Returns a list of `Ty`s for each upvar. // Returns a list of `Ty`s for each upvar.
fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> { fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> {
// Presently an unboxed closure type cannot "escape" out of a
// function, so we will only encounter ones that originated in the
// local crate or were inlined into it along with some function.
// This may change if abstract return types of some sort are
// implemented.
self.typeck_results self.typeck_results
.borrow() .borrow()
.closure_min_captures_flattened(closure_id) .closure_min_captures_flattened(closure_id)

View File

@ -895,7 +895,7 @@ fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<
fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> { fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> {
CheckWfFcxBuilder { CheckWfFcxBuilder {
inherited: Inherited::build(tcx, def_id).reveal_defining_opaque_types(), inherited: Inherited::build(tcx, def_id),
id: hir::HirId::make_owner(def_id), id: hir::HirId::make_owner(def_id),
span, span,
param_env: tcx.param_env(def_id), param_env: tcx.param_env(def_id),

View File

@ -18,6 +18,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt}; use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::opaque_types::InferCtxtExt;
use std::mem; use std::mem;
@ -64,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
wbcx.visit_closures(); wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs(); wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types(); wbcx.visit_fru_field_types();
wbcx.visit_opaque_types(); wbcx.visit_opaque_types(body.value.span);
wbcx.visit_coercion_casts(); wbcx.visit_coercion_casts();
wbcx.visit_user_provided_tys(); wbcx.visit_user_provided_tys();
wbcx.visit_user_provided_sigs(); wbcx.visit_user_provided_sigs();
@ -495,18 +496,64 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fcx_typeck_results.generator_interior_types.clone(); fcx_typeck_results.generator_interior_types.clone();
} }
#[instrument(skip(self), level = "debug")] #[instrument(skip(self, span), level = "debug")]
fn visit_opaque_types(&mut self) { fn visit_opaque_types(&mut self, span: Span) {
let opaque_types = let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone();
self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); for (opaque_type_key, opaque_defn) in opaque_types {
for (opaque_type_key, decl) in opaque_types { let hir_id =
let hidden_type = match decl.origin { self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local());
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => { let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
Some(self.resolve(decl.hidden_type.ty, &decl.hidden_type.span))
debug_assert!(!instantiated_ty.has_escaping_bound_vars());
let opaque_type_key = self.fcx.fully_resolve(opaque_type_key).unwrap();
// Prevent:
// * `fn foo<T>() -> Foo<T>`
// * `fn foo<T: Bound + Other>() -> Foo<T>`
// from being defining.
// Also replace all generic params with the ones from the opaque type
// definition so that
// ```rust
// type Foo<T> = impl Baz + 'static;
// fn foo<U>() -> Foo<U> { .. }
// ```
// figures out the concrete type with `U`, but the stored type is with `T`.
// FIXME: why are we calling this here? This seems too early, and duplicated.
let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
opaque_type_key,
instantiated_ty,
span,
);
let mut skip_add = false;
if let ty::Opaque(definition_ty_def_id, _substs) = *definition_ty.kind() {
if opaque_defn.origin == hir::OpaqueTyOrigin::TyAlias {
if opaque_type_key.def_id == definition_ty_def_id {
debug!(
"skipping adding concrete definition for opaque type {:?} {:?}",
opaque_defn, opaque_type_key.def_id
);
skip_add = true;
}
} }
hir::OpaqueTyOrigin::TyAlias => None, }
};
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type); if opaque_type_key.substs.needs_infer() {
span_bug!(span, "{:#?} has inference variables", opaque_type_key.substs)
}
// We only want to add an entry into `concrete_opaque_types`
// if we actually found a defining usage of this opaque type.
// Otherwise, we do nothing - we'll either find a defining usage
// in some other location, or we'll end up emitting an error due
// to the lack of defining usage
if !skip_add {
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id);
}
} }
} }

View File

@ -389,22 +389,28 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
.get_value_matching(|(key, _)| key.def_id == def_id.to_def_id()) .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
.copied() .copied()
.unwrap_or_else(|| { .unwrap_or_else(|| {
let table = tcx.typeck(owner); tcx.sess.delay_span_bug(
if let Some(ErrorReported) = table.tainted_by_errors { DUMMY_SP,
&format!(
"owner {:?} has no opaque type for {:?} in its typeck results",
owner, def_id,
),
);
if let Some(ErrorReported) =
tcx.typeck(owner).tainted_by_errors
{
// Some error in the // Some error in the
// owner fn prevented us from populating // owner fn prevented us from populating
// the `concrete_opaque_types` table. // the `concrete_opaque_types` table.
tcx.ty_error() tcx.ty_error()
} else { } else {
table.concrete_opaque_types.get(&def_id.to_def_id()).copied().unwrap_or_else(|| { // We failed to resolve the opaque type or it
// We failed to resolve the opaque type or it // resolves to itself. Return the non-revealed
// resolves to itself. We interpret this as the // type, which should result in E0720.
// no values of the hidden type ever being constructed, tcx.mk_opaque(
// so we can just make the hidden type be `!`. def_id.to_def_id(),
// For backwards compatibility reasons, we fall back to InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
// `()` until we the diverging default is changed. )
Some(tcx.mk_diverging_default())
}).expect("RPIT always have a hidden type from typeck")
} }
}); });
debug!("concrete_ty = {:?}", concrete_ty); debug!("concrete_ty = {:?}", concrete_ty);
@ -599,21 +605,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
} }
// Calling `mir_borrowck` can lead to cycle errors through // Calling `mir_borrowck` can lead to cycle errors through
// const-checking, avoid calling it if we don't have to. // const-checking, avoid calling it if we don't have to.
// ```rust if !self.tcx.typeck(def_id).concrete_opaque_types.contains(&self.def_id) {
// type Foo = impl Fn() -> usize; // when computing type for this
// const fn bar() -> Foo {
// || 0usize
// }
// const BAZR: Foo = bar(); // we would mir-borrowck this, causing cycles
// // because we again need to reveal `Foo` so we can check whether the
// // constant does not contain interior mutability.
// ```
let tables = self.tcx.typeck(def_id);
if let Some(_) = tables.tainted_by_errors {
self.found = Some((DUMMY_SP, self.tcx.ty_error()));
return;
}
if tables.concrete_opaque_types.get(&self.def_id).is_none() {
debug!("no constraints in typeck results"); debug!("no constraints in typeck results");
return; return;
} }
@ -667,7 +659,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
intravisit::walk_expr(self, ex); intravisit::walk_expr(self, ex);
} }
fn visit_item(&mut self, it: &'tcx Item<'tcx>) { fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
trace!(?it.def_id); debug!("find_existential_constraints: visiting {:?}", it);
// The opaque type itself or its children are not within its reveal scope. // The opaque type itself or its children are not within its reveal scope.
if it.def_id.to_def_id() != self.def_id { if it.def_id.to_def_id() != self.def_id {
self.check(it.def_id); self.check(it.def_id);
@ -675,7 +667,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
} }
} }
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
trace!(?it.def_id); debug!("find_existential_constraints: visiting {:?}", it);
// The opaque type itself or its children are not within its reveal scope. // The opaque type itself or its children are not within its reveal scope.
if it.def_id.to_def_id() != self.def_id { if it.def_id.to_def_id() != self.def_id {
self.check(it.def_id); self.check(it.def_id);
@ -683,7 +675,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
} }
} }
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
trace!(?it.def_id); debug!("find_existential_constraints: visiting {:?}", it);
self.check(it.def_id); self.check(it.def_id);
intravisit::walk_trait_item(self, it); intravisit::walk_trait_item(self, it);
} }
@ -693,12 +685,12 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
let scope = tcx.hir().get_defining_scope(hir_id); let scope = tcx.hir().get_defining_scope(hir_id);
let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None }; let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None };
debug!(?scope); debug!("find_opaque_ty_constraints: scope={:?}", scope);
if scope == hir::CRATE_HIR_ID { if scope == hir::CRATE_HIR_ID {
tcx.hir().walk_toplevel_module(&mut locator); tcx.hir().walk_toplevel_module(&mut locator);
} else { } else {
trace!("scope={:#?}", tcx.hir().get(scope)); debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
match tcx.hir().get(scope) { match tcx.hir().get(scope) {
// We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
// This allows our visitor to process the defining item itself, causing // This allows our visitor to process the defining item itself, causing
@ -725,12 +717,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
Some((_, ty)) => ty, Some((_, ty)) => ty,
None => { None => {
let span = tcx.def_span(def_id); let span = tcx.def_span(def_id);
let name = tcx.item_name(tcx.parent(def_id.to_def_id()).unwrap()); tcx.sess.span_err(span, "could not find defining uses");
let label = format!(
"`{}` must be used in combination with a concrete type within the same module",
name
);
tcx.sess.struct_span_err(span, "unconstrained opaque type").note(&label).emit();
tcx.ty_error() tcx.ty_error()
} }
} }

View File

@ -427,7 +427,6 @@ fn trait_predicate_kind<'tcx>(
| ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None, | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
} }
} }

View File

@ -59,7 +59,6 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
| ty::PredicateKind::Coerce(..) | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => (), | ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
} }
} }

View File

@ -147,12 +147,6 @@ fn main() {
cmd.arg("-Z").arg("force-unstable-if-unmarked"); cmd.arg("-Z").arg("force-unstable-if-unmarked");
} }
if let Ok(flags) = env::var("MAGIC_EXTRA_RUSTFLAGS") {
for flag in flags.split(' ') {
cmd.arg(flag);
}
}
let is_test = args.iter().any(|a| a == "--test"); let is_test = args.iter().any(|a| a == "--test");
if verbose > 2 { if verbose > 2 {
let rust_env_vars = let rust_env_vars =

View File

@ -297,7 +297,6 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
| ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"), | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
} }
} }

View File

@ -305,7 +305,7 @@ pub fn return_impl_trait() -> i32 {
} }
#[cfg(not(any(cfail1,cfail4)))] #[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")] #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")]
#[rustc_clean(cfg = "cfail3")] #[rustc_clean(cfg = "cfail3")]
#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")] #[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")]
#[rustc_clean(cfg = "cfail6")] #[rustc_clean(cfg = "cfail6")]

View File

@ -30,7 +30,7 @@ impl Thing for AssocNoCopy {
type Out = Box<dyn Bar<Assoc: Copy>>; type Out = Box<dyn Bar<Assoc: Copy>>;
fn func() -> Self::Out { fn func() -> Self::Out {
Box::new(AssocNoCopy)
//~^ ERROR the trait bound `String: Copy` is not satisfied //~^ ERROR the trait bound `String: Copy` is not satisfied
Box::new(AssocNoCopy)
} }
} }

View File

@ -1,10 +1,8 @@
error[E0277]: the trait bound `String: Copy` is not satisfied error[E0277]: the trait bound `String: Copy` is not satisfied
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:33:9 --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:32:18
| |
LL | Box::new(AssocNoCopy) LL | fn func() -> Self::Out {
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | ^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
= note: required for the cast to the object type `dyn Bar<Assoc = <AssocNoCopy as Thing>::Out::{opaque#0}>`
error: aborting due to previous error error: aborting due to previous error

View File

@ -23,8 +23,8 @@ fn bar() -> impl Bar {
} }
fn baz() -> impl Bar<Item = i32> { fn baz() -> impl Bar<Item = i32> {
//~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
bar() bar()
//~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
} }
fn main() { fn main() {

View File

@ -1,16 +1,14 @@
error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32` error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
--> $DIR/impl-trait-return-missing-constraint.rs:26:5 --> $DIR/impl-trait-return-missing-constraint.rs:25:13
| |
LL | fn bar() -> impl Bar { LL | fn bar() -> impl Bar {
| -------- the expected opaque type | -------- the found opaque type
... ...
LL | bar() LL | fn baz() -> impl Bar<Item = i32> {
| ^^^^^ expected associated type, found `i32` | ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
| |
= note: expected associated type `<impl Bar as Foo>::Item` = note: expected type `i32`
found type `i32` found associated type `<impl Bar as Foo>::Item`
= help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32` or calling a method that returns `<impl Bar as Foo>::Item`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32` help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
| |
LL | fn bar() -> impl Bar<Item = i32> { LL | fn bar() -> impl Bar<Item = i32> {

View File

@ -8,10 +8,10 @@ LL | Box::new(async { x } )
| may outlive borrowed value `x` | may outlive borrowed value `x`
| |
note: async block is returned here note: async block is returned here
--> $DIR/async-borrowck-escaping-block-error.rs:6:5 --> $DIR/async-borrowck-escaping-block-error.rs:4:20
| |
LL | Box::new(async { x } ) LL | fn test_boxed() -> Box<impl std::future::Future<Output = u32>> {
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword
| |
LL | Box::new(async move { x } ) LL | Box::new(async move { x } )

View File

@ -13,9 +13,9 @@ impl Client {
async fn get() { } async fn get() { }
pub fn foo() -> impl Future + Send { pub fn foo() -> impl Future + Send {
//~^ ERROR future cannot be sent between threads safely
let client = Client(Box::new(true)); let client = Client(Box::new(true));
async move { async move {
//~^ ERROR future cannot be sent between threads safely
match client.status() { match client.status() {
200 => { 200 => {
let _x = get().await; let _x = get().await;

View File

@ -1,8 +1,8 @@
error: future cannot be sent between threads safely error: future cannot be sent between threads safely
--> $DIR/issue-64130-4-async-move.rs:17:5 --> $DIR/issue-64130-4-async-move.rs:15:17
| |
LL | async move { LL | pub fn foo() -> impl Future + Send {
| ^^^^^^^^^^ future created by async block is not `Send` | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
| |
= help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)` = help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)`
note: future is not `Send` as this value is used across an await note: future is not `Send` as this value is used across an await

View File

@ -2,8 +2,8 @@
use std::future::Future; use std::future::Future;
fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
//~^ Error future cannot be sent between threads safely
async { (ty, ty1) } async { (ty, ty1) }
//~^ Error future cannot be sent between threads safely
} }
fn main() {} fn main() {}

View File

@ -1,11 +1,11 @@
error: future cannot be sent between threads safely error: future cannot be sent between threads safely
--> $DIR/issue-70818.rs:5:5 --> $DIR/issue-70818.rs:4:38
| |
LL | async { (ty, ty1) } LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
| ^^^^^ future created by async block is not `Send` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
| |
note: captured value is not `Send` note: captured value is not `Send`
--> $DIR/issue-70818.rs:5:18 --> $DIR/issue-70818.rs:6:18
| |
LL | async { (ty, ty1) } LL | async { (ty, ty1) }
| ^^^ has type `U` which is not `Send` | ^^^ has type `U` which is not `Send`

View File

@ -8,8 +8,8 @@ async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
} }
fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
//~^ ERROR: future cannot be sent between threads safely
async move { async move {
//~^ ERROR: future cannot be sent between threads safely
baz(|| async{ baz(|| async{
foo(tx.clone()); foo(tx.clone());
}).await; }).await;

View File

@ -1,8 +1,8 @@
error: future cannot be sent between threads safely error: future cannot be sent between threads safely
--> $DIR/issue-70935-complex-spans.rs:11:5 --> $DIR/issue-70935-complex-spans.rs:10:45
| |
LL | async move { LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
| ^^^^^^^^^^ future created by async block is not `Send` | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
| |
= help: the trait `Sync` is not implemented for `Sender<i32>` = help: the trait `Sync` is not implemented for `Sender<i32>`
note: future is not `Send` as this value is used across an await note: future is not `Send` as this value is used across an await

View File

@ -14,16 +14,12 @@ LL | | }
= help: consider adding the following bound: `'a: 'b` = help: consider adding the following bound: `'a: 'b`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ret-impl-trait-one.rs:16:80 --> $DIR/ret-impl-trait-one.rs:16:65
| |
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
| ____________________________________--__________________________________________^ | -- ^^^^^^^^^^^^^^
| | | | |
| | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
LL | |
LL | | (a, b)
LL | | }
| |_^
| |
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
| |

View File

@ -1,26 +1,19 @@
error[E0623]: lifetime mismatch error[E0623]: lifetime mismatch
--> $DIR/ret-impl-trait-one.rs:10:85 --> $DIR/ret-impl-trait-one.rs:10:65
| |
LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b { LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
| ______________________________________________________------_____-------------------_^ | ------ ^^^^^^^^^^^^^^^^^^^
| | | | | |
| | this parameter and the return type are declared with different lifetimes... | | ...but data from `a` is returned here
LL | | | this parameter and the return type are declared with different lifetimes...
LL | | (a, b)
LL | | }
| |_^ ...but data from `a` is returned here
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ret-impl-trait-one.rs:16:80 --> $DIR/ret-impl-trait-one.rs:16:65
| |
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
| ____________________________________--__________________________________________^ | -- ^^^^^^^^^^^^^^
| | | | |
| | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
LL | |
LL | | (a, b)
LL | | }
| |_^
| |
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
| |

View File

@ -3,4 +3,3 @@
pub const async fn x() {} pub const async fn x() {}
//~^ ERROR functions cannot be both `const` and `async` //~^ ERROR functions cannot be both `const` and `async`
//~| ERROR cycle detected

View File

@ -7,36 +7,5 @@ LL | pub const async fn x() {}
| | `async` because of this | | `async` because of this
| `const` because of this | `const` because of this
error[E0391]: cycle detected when computing type of `x::{opaque#0}` error: aborting due to previous error
--> $DIR/no-const-async.rs:4:24
|
LL | pub const async fn x() {}
| ^
|
note: ...which requires borrow-checking `x`...
--> $DIR/no-const-async.rs:4:1
|
LL | pub const async fn x() {}
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `x`...
--> $DIR/no-const-async.rs:4:1
|
LL | pub const async fn x() {}
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const checking `x`...
--> $DIR/no-const-async.rs:4:1
|
LL | pub const async fn x() {}
| ^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
= note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
= note: ...which again requires computing type of `x::{opaque#0}`, completing the cycle
note: cycle used when checking item types in top-level module
--> $DIR/no-const-async.rs:4:1
|
LL | pub const async fn x() {}
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0391`.

View File

@ -2,8 +2,7 @@
// Test that impl trait does not allow creating recursive types that are // Test that impl trait does not allow creating recursive types that are
// otherwise forbidden when using `async` and `await`. // otherwise forbidden when using `async` and `await`.
async fn recursive_async_function() -> () { async fn recursive_async_function() -> () { //~ ERROR
//~^ ERROR recursion in an `async fn` requires boxing
recursive_async_function().await; recursive_async_function().await;
} }

View File

@ -21,6 +21,7 @@ async fn dummy() {}
async fn suggest_await_in_async_fn_return() { async fn suggest_await_in_async_fn_return() {
dummy() dummy()
//~^ ERROR mismatched types [E0308] //~^ ERROR mismatched types [E0308]
//~| HELP consider using a semicolon here
//~| HELP consider `await`ing on the `Future` //~| HELP consider `await`ing on the `Future`
//~| SUGGESTION .await //~| SUGGESTION .await
} }

View File

@ -33,9 +33,13 @@ help: consider `await`ing on the `Future`
| |
LL | dummy().await LL | dummy().await
| ++++++ | ++++++
help: consider using a semicolon here
|
LL | dummy();
| +
error[E0308]: `if` and `else` have incompatible types error[E0308]: `if` and `else` have incompatible types
--> $DIR/suggest-missing-await.rs:34:9 --> $DIR/suggest-missing-await.rs:35:9
| |
LL | let _x = if true { LL | let _x = if true {
| ______________- | ______________-
@ -49,20 +53,15 @@ LL | |
LL | | }; LL | | };
| |_____- `if` and `else` have incompatible types | |_____- `if` and `else` have incompatible types
| |
note: while checking the return type of the `async fn` = note: expected type `impl Future<Output = ()>`
--> $DIR/suggest-missing-await.rs:18:18 found unit type `()`
|
LL | async fn dummy() {}
| ^ checked the `Output` of this `async fn`, expected opaque type
= note: expected opaque type `impl Future<Output = ()>`
found unit type `()`
help: consider `await`ing on the `Future` help: consider `await`ing on the `Future`
| |
LL | dummy().await LL | dummy().await
| ++++++ | ++++++
error[E0308]: `match` arms have incompatible types error[E0308]: `match` arms have incompatible types
--> $DIR/suggest-missing-await.rs:44:14 --> $DIR/suggest-missing-await.rs:45:14
| |
LL | let _x = match 0usize { LL | let _x = match 0usize {
| ______________- | ______________-
@ -90,7 +89,7 @@ LL ~ 1 => dummy().await,
| |
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:52:9 --> $DIR/suggest-missing-await.rs:53:9
| |
LL | () => {} LL | () => {}
| ^^ expected opaque type, found `()` | ^^ expected opaque type, found `()`
@ -108,13 +107,13 @@ LL | let _x = match dummy().await {
| ++++++ | ++++++
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:66:9 --> $DIR/suggest-missing-await.rs:67:9
| |
LL | Ok(_) => {} LL | Ok(_) => {}
| ^^^^^ expected opaque type, found enum `Result` | ^^^^^ expected opaque type, found enum `Result`
| |
note: while checking the return type of the `async fn` note: while checking the return type of the `async fn`
--> $DIR/suggest-missing-await.rs:56:28 --> $DIR/suggest-missing-await.rs:57:28
| |
LL | async fn dummy_result() -> Result<(), ()> { LL | async fn dummy_result() -> Result<(), ()> {
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type | ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
@ -126,13 +125,13 @@ LL | match dummy_result().await {
| ++++++ | ++++++
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:68:9 --> $DIR/suggest-missing-await.rs:69:9
| |
LL | Err(_) => {} LL | Err(_) => {}
| ^^^^^^ expected opaque type, found enum `Result` | ^^^^^^ expected opaque type, found enum `Result`
| |
note: while checking the return type of the `async fn` note: while checking the return type of the `async fn`
--> $DIR/suggest-missing-await.rs:56:28 --> $DIR/suggest-missing-await.rs:57:28
| |
LL | async fn dummy_result() -> Result<(), ()> { LL | async fn dummy_result() -> Result<(), ()> {
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type | ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type

View File

@ -18,5 +18,5 @@ fn main() {
// this is an `*mut fmt::Debug` in practice // this is an `*mut fmt::Debug` in practice
let mut b_raw = Box::into_raw(b); let mut b_raw = Box::into_raw(b);
// ... and they should not be mixable // ... and they should not be mixable
b_raw = f_raw as *mut _; //~ ERROR mismatched types b_raw = f_raw as *mut _; //~ ERROR is invalid
} }

Some files were not shown because too many files have changed in this diff Show More