Auto merge of #94081 - oli-obk:lazy_tait_take_two, r=nikomatsakis

Lazy type-alias-impl-trait take two

### user visible change 1: RPIT inference from recursive call sites

Lazy TAIT has an insta-stable change. The following snippet now compiles, because opaque types can now have their hidden type set from wherever the opaque type is mentioned.

```rust
fn bar(b: bool) -> impl std::fmt::Debug {
    if b {
        return 42
    }
    let x: u32 = bar(false); // this errors on stable
    99
}
```

The return type of `bar` stays opaque, you can't do `bar(false) + 42`, you need to actually mention the hidden type.

### user visible change 2: divergence between RPIT and TAIT in return statements

Note that `return` statements and the trailing return expression are special with RPIT (but not TAIT). So

```rust
#![feature(type_alias_impl_trait)]
type Foo = impl std::fmt::Debug;

fn foo(b: bool) -> Foo {
    if b {
        return vec![42];
    }
    std::iter::empty().collect() //~ ERROR `Foo` cannot be built from an iterator
}

fn bar(b: bool) -> impl std::fmt::Debug {
    if b {
        return vec![42]
    }
    std::iter::empty().collect() // Works, magic (accidentally stabilized, not intended)
}
```

But when we are working with the return value of a recursive call, the behavior of RPIT and TAIT is the same:

```rust
type Foo = impl std::fmt::Debug;

fn foo(b: bool) -> Foo {
    if b {
        return vec![];
    }
    let mut x = foo(false);
    x = std::iter::empty().collect(); //~ ERROR `Foo` cannot be built from an iterator
    vec![]
}

fn bar(b: bool) -> impl std::fmt::Debug {
    if b {
        return vec![];
    }
    let mut x = bar(false);
    x = std::iter::empty().collect(); //~ ERROR `impl Debug` cannot be built from an iterator
    vec![]
}
```

### user visible change 3: TAIT does not merge types across branches

In contrast to RPIT, TAIT does not merge types across branches, so the following does not compile.

```rust
type Foo = impl std::fmt::Debug;

fn foo(b: bool) -> Foo {
    if b {
        vec![42_i32]
    } else {
        std::iter::empty().collect()
        //~^ ERROR `Foo` cannot be built from an iterator over elements of type `_`
    }
}
```

It is easy to support, but we should make an explicit decision to include the additional complexity in the implementation (it's not much, see a721052457cf513487fb4266e3ade65c29b272d2 which needs to be reverted to enable this).

### PR formalities

previous attempt: #92007

This PR also includes #92306 and #93783, as they were reverted along with #92007 in #93893

fixes #93411
fixes #88236
fixes #89312
fixes #87340
fixes #86800
fixes #86719
fixes #84073
fixes #83919
fixes #82139
fixes #77987
fixes #74282
fixes #67830
fixes #62742
fixes #54895
This commit is contained in:
bors 2022-03-30 05:04:45 +00:00
commit f132bcf3bd
419 changed files with 5208 additions and 2490 deletions

View File

@ -2,9 +2,13 @@ use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_infer::infer::region_constraints::Constraint;
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::RegionVariableOrigin;
use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::RegionVid;
use rustc_middle::ty::UniverseIndex;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op;
@ -76,6 +80,15 @@ crate trait ToUniverseInfo<'tcx> {
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
}
impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
base_universe: Some(base_universe),
..self
})))
}
}
impl<'tcx> ToUniverseInfo<'tcx>
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
{
@ -116,6 +129,12 @@ impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::Custo
}
}
impl<'tcx> ToUniverseInfo<'tcx> for ! {
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
self
}
}
#[allow(unused_lifetimes)]
trait TypeOpInfo<'tcx> {
/// Returns an error to be reported if rerunning the type op fails to
@ -130,7 +149,7 @@ trait TypeOpInfo<'tcx> {
fn nice_error(
&self,
tcx: TyCtxt<'tcx>,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
@ -175,7 +194,7 @@ trait TypeOpInfo<'tcx> {
debug!(?placeholder_region);
let span = cause.span;
let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
if let Some(nice_error) = nice_error {
mbcx.buffer_error(nice_error);
@ -208,16 +227,16 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
fn nice_error(
&self,
tcx: TyCtxt<'tcx>,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
tcx.infer_ctxt().enter_with_canonical(
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
cause.span,
&self.canonical_query,
|ref infcx, key, _| {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
try_extract_error_from_fulfill_cx(
fulfill_cx,
@ -255,16 +274,16 @@ where
fn nice_error(
&self,
tcx: TyCtxt<'tcx>,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
tcx.infer_ctxt().enter_with_canonical(
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
cause.span,
&self.canonical_query,
|ref infcx, key, _| {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
let mut selcx = SelectionContext::new(infcx);
@ -316,16 +335,16 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
fn nice_error(
&self,
tcx: TyCtxt<'tcx>,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
tcx.infer_ctxt().enter_with_canonical(
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
cause.span,
&self.canonical_query,
|ref infcx, key, _| {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
.ok()?;
try_extract_error_from_fulfill_cx(
@ -339,6 +358,43 @@ 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, ErrorGuaranteed> {
// 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, ErrorGuaranteed>> {
try_extract_error_from_region_constraints(
mbcx.infcx,
placeholder_region,
error_region,
self.region_constraints.as_ref().unwrap(),
// We're using the original `InferCtxt` that we
// started MIR borrowchecking with, so the region
// constraints have already been taken. Use the data from
// our `mbcx` instead.
|vid| mbcx.regioncx.var_infos[vid].origin,
|vid| mbcx.regioncx.var_infos[vid].universe,
)
}
}
#[instrument(skip(fulfill_cx, infcx), level = "debug")]
fn try_extract_error_from_fulfill_cx<'tcx>(
mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
@ -346,15 +402,30 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
let tcx = infcx.tcx;
// We generally shouldn't have errors here because the query was
// already run, but there's no point using `delay_span_bug`
// when we're going to emit an error here anyway.
let _errors = fulfill_cx.select_all_or_error(infcx);
let region_constraints = infcx.with_region_constraints(|r| r.clone());
try_extract_error_from_region_constraints(
infcx,
placeholder_region,
error_region,
&region_constraints,
|vid| infcx.region_var_origin(vid),
|vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))),
)
}
let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
debug!("{:#?}", region_constraints);
fn try_extract_error_from_region_constraints<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<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, ErrorGuaranteed>> {
let (sub_region, cause) =
region_constraints.constraints.iter().find_map(|(constraint, cause)| {
match *constraint {
Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
@ -362,12 +433,11 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
}
// FIXME: Should this check the universe of the var?
Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone()))
}
_ => None,
}
})
})?;
})?;
debug!(?sub_region, "cause = {:#?}", cause);
let nice_error = match (error_region, *sub_region) {
@ -375,7 +445,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
infcx,
RegionResolutionError::SubSupConflict(
vid,
infcx.region_var_origin(vid),
region_var_origin(vid),
cause.clone(),
error_region,
cause.clone(),
@ -392,8 +462,8 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
infcx,
RegionResolutionError::UpperBoundUniverseConflict(
vid,
infcx.region_var_origin(vid),
infcx.universe_of_region(sub_region),
region_var_origin(vid),
universe_of_region(vid),
cause.clone(),
placeholder_region,
),

View File

@ -7,6 +7,7 @@
#![feature(let_chains)]
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(stmt_expr_attributes)]
#![feature(trusted_step)]
#![feature(try_blocks)]
@ -125,8 +126,9 @@ fn mir_borrowck<'tcx>(
) -> &'tcx BorrowCheckResult<'tcx> {
let (input_body, promoted) = tcx.mir_promoted(def);
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(def.did).enter(|infcx| {
let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| {
let input_body: &Body<'_> = &input_body.borrow();
let promoted: &IndexVec<_, _> = &promoted.borrow();
do_mir_borrowck(&infcx, input_body, promoted, false).0
@ -141,7 +143,7 @@ fn mir_borrowck<'tcx>(
/// 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
/// facts.
#[instrument(skip(infcx, input_body, input_promoted), level = "debug")]
#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")]
fn do_mir_borrowck<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
input_body: &Body<'tcx>,

View File

@ -8,7 +8,7 @@ use rustc_middle::mir::{
BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
Promoted,
};
use rustc_middle::ty::{self, OpaqueTypeKey, Region, RegionVid, Ty};
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid};
use rustc_span::symbol::sym;
use std::env;
use std::fmt::Debug;
@ -43,7 +43,7 @@ pub type PoloniusOutput = Output<RustcFacts>;
/// closure requirements to propagate, and any generated errors.
crate struct NllOutput<'tcx> {
pub regioncx: RegionInferenceContext<'tcx>,
pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
pub polonius_input: Option<Box<AllFacts>>,
pub polonius_output: Option<Rc<PoloniusOutput>>,
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
@ -305,7 +305,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
infcx.set_tainted_by_errors();
}
let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values, body.span);
let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values);
NllOutput {
regioncx,
@ -372,7 +372,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
errors: &mut crate::error::BorrowckErrors<'tcx>,
) {
let tcx = infcx.tcx;

View File

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

View File

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

View File

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

View File

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

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.
let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
let output_span = body.local_decls[RETURN_PLACE].source_info.span;
if let Err(terr) = self.eq_opaque_type_and_type(
mir_output_ty,
if let Err(terr) = self.eq_types(
normalized_output_ty,
mir_output_ty,
Locations::All(output_span),
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 =
self.normalize(user_provided_output_ty, Locations::All(output_span));
if let Err(err) = self.eq_opaque_type_and_type(
mir_output_ty,
if let Err(err) = self.eq_types(
user_provided_output_ty,
mir_output_ty,
Locations::All(output_span),
ConstraintCategory::BoringNoLocation,
) {

View File

@ -5,6 +5,7 @@ use std::{fmt, iter, mem};
use either::Either;
use hir::OpaqueTyOrigin;
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::vec_map::VecMap;
@ -15,8 +16,8 @@ use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin,
@ -30,8 +31,8 @@ use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
use rustc_middle::ty::{
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType,
OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
};
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{Span, DUMMY_SP};
@ -39,9 +40,11 @@ use rustc_target::abi::VariantIdx;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
use rustc_trait_selection::traits::query::Fallible;
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
use rustc_const_eval::transform::{
check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
@ -75,7 +78,7 @@ macro_rules! span_mirbug {
$context.last_span,
&format!(
"broken MIR in {:?} ({:?}): {}",
$context.body.source.def_id(),
$context.body().source.def_id(),
$elem,
format_args!($($message)*),
),
@ -199,59 +202,44 @@ pub(crate) fn type_check<'mir, 'tcx>(
);
translate_outlives_facts(&mut cx);
let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
let opaque_type_values =
infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
opaque_type_values
.into_iter()
.filter_map(|(opaque_type_key, mut decl)| {
decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
.map(|(opaque_type_key, decl)| {
cx.fully_perform_op(
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);
trace!(
"finalized opaque type {:?} to {:#?}",
opaque_type_key,
decl.concrete_ty.kind()
hidden_type.ty.kind()
);
if decl.concrete_ty.has_infer_types_or_consts() {
if hidden_type.has_infer_types_or_consts() {
infcx.tcx.sess.delay_span_bug(
body.span,
&format!("could not resolve {:#?}", decl.concrete_ty.kind()),
decl.hidden_type.span,
&format!("could not resolve {:#?}", hidden_type.ty.kind()),
);
decl.concrete_ty = infcx.tcx.ty_error();
hidden_type.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
};
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))
}
(opaque_type_key, (hidden_type, decl.origin))
})
.collect()
},
@ -283,7 +271,7 @@ fn type_check_internal<'a, 'tcx, R>(
borrowck_context,
);
let errors_reported = {
let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
let mut verifier = TypeVerifier::new(&mut checker, promoted);
verifier.visit_body(&body);
verifier.errors_reported
};
@ -340,7 +328,6 @@ enum FieldAccessError {
/// is a problem.
struct TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
body: &'b Body<'tcx>,
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
last_span: Span,
errors_reported: bool,
@ -476,7 +463,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: 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);
}
@ -535,10 +522,13 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
fn new(
cx: &'a mut TypeChecker<'b, 'tcx>,
body: &'b Body<'tcx>,
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
) -> Self {
TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false }
TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false }
}
fn body(&self) -> &Body<'tcx> {
self.cx.body
}
fn tcx(&self) -> TyCtxt<'tcx> {
@ -563,7 +553,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
) -> PlaceTy<'tcx> {
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() {
if place_ty.variant_index.is_none() {
@ -608,7 +598,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// checker on the promoted MIR, then transfer the constraints back to
// the main MIR, changing the locations to the provided location.
let parent_body = mem::replace(&mut self.body, promoted_body);
let parent_body = mem::replace(&mut self.cx.body, promoted_body);
// Use new sets of constraints and closure bounds so that we can
// modify their locations.
@ -644,7 +634,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
self.cx.typeck_mir(promoted_body);
}
self.body = parent_body;
self.cx.body = parent_body;
// Merge the outlives constraints back in, at the given location.
swap_constraints(self);
@ -706,7 +696,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}))
}
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 {
PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i))
} else {
@ -915,7 +905,7 @@ struct BorrowCheckContext<'a, 'tcx> {
crate struct MirTypeckResults<'tcx> {
crate constraints: MirTypeckRegionConstraints<'tcx>,
crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
}
/// A collection of region constraints that must be satisfied for the
@ -1065,17 +1055,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
checker
}
fn body(&self) -> &Body<'tcx> {
self.body
}
fn unsized_feature_enabled(&self) -> bool {
let features = self.tcx().features();
features.unsized_locals || features.unsized_fn_params
}
/// Equate the inferred type and the annotated type for user type annotations
#[instrument(skip(self), level = "debug")]
fn check_user_type_annotations(&mut self) {
debug!(
"check_user_type_annotations: user_type_annotations={:?}",
self.user_type_annotations
);
debug!(?self.user_type_annotations);
for user_annotation in self.user_type_annotations {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
@ -1216,131 +1208,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
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> {
self.infcx.tcx
}
@ -2772,19 +2639,31 @@ impl NormalizeLocation for Location {
}
}
#[derive(Debug, Default)]
struct ObligationAccumulator<'tcx> {
obligations: PredicateObligations<'tcx>,
/// Runs `infcx.instantiate_opaque_types`. Unlike other `TypeOp`s,
/// this is not canonicalized - it directly affects the main `InferCtxt`
/// that we use during MIR borrowchecking.
#[derive(Debug)]
pub(super) struct InstantiateOpaqueType<'tcx> {
pub base_universe: Option<ty::UniverseIndex>,
pub region_constraints: Option<RegionConstraintData<'tcx>>,
pub obligations: Vec<PredicateObligation<'tcx>>,
}
impl<'tcx> ObligationAccumulator<'tcx> {
fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
let InferOk { value, obligations } = value;
self.obligations.extend(obligations);
value
}
impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
type Output = ();
/// We use this type itself to store the information used
/// when reporting errors. Since this is not a query, we don't
/// re-run anything during error reporting - we just use the information
/// we saved to help extract an error from the already-existing region
/// constraints in our `InferCtxt`
type ErrorInfo = InstantiateOpaqueType<'tcx>;
fn into_vec(self) -> PredicateObligations<'tcx> {
self.obligations
fn fully_perform(mut self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
let (mut output, region_constraints) = scrape_region_constraints(infcx, || {
Ok(InferOk { value: (), obligations: self.obligations.clone() })
})?;
self.region_constraints = Some(region_constraints);
output.error_info = Some(self);
Ok(output)
}
}

View File

@ -1,13 +1,16 @@
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{self, Const, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits::query::Fallible;
use crate::constraints::OutlivesConstraint;
use crate::diagnostics::UniverseInfo;
use crate::type_check::{Locations, TypeChecker};
use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker};
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
@ -63,6 +66,10 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, '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> {
self.type_checker.param_env
}
@ -117,6 +124,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
// We don't have to worry about the equality of consts during borrow checking
// 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: Const<'tcx>, _b: Const<'tcx>) {}
fn normalization() -> NormalizationStrategy {
@ -126,4 +136,34 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
fn forbid_inference_vars() -> bool {
true
}
fn register_opaque_type(
&mut self,
a: Ty<'tcx>,
b: Ty<'tcx>,
a_is_expected: bool,
) -> Result<(), TypeError<'tcx>> {
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 {
obligations: self
.type_checker
.infcx
.handle_opaque_type(a, b, a_is_expected, &cause, param_env)?
.obligations,
// These fields are filled in during exectuion of the operation
base_universe: None,
region_constraints: None,
},
)
.unwrap();
Ok(())
}
}

View File

@ -725,6 +725,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
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>(
&self,
origin: NllRegionVariableOrigin,
@ -735,22 +736,15 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
where
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| {
debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
debug!(?br);
let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: all_outlive_scope.to_def_id(),
bound_region: br.kind,
}));
let region_vid = self.next_nll_region_var(origin);
indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
debug!(
"replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}",
liberated_region, region_vid
);
debug!(?liberated_region, ?region_vid);
region_vid
});
value
@ -765,6 +759,7 @@ 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
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the
/// inputs vector.
#[instrument(skip(self, indices))]
fn replace_late_bound_regions_with_nll_infer_vars(
&self,
mir_def_id: LocalDefId,
@ -776,6 +771,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
debug!(?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::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
@ -47,7 +47,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
location: Location,
) -> bool {
let ty = ccx.body.local_decls[local].ty;
if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
// Peeking into opaque types causes cycles if the current function declares said opaque
// 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;
}
@ -101,7 +104,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
location: Location,
) -> bool {
let ty = ccx.body.local_decls[local].ty;
if !HasMutInterior::in_any_value_of_ty(ccx, ty) {
// Peeking into opaque types causes cycles if the current function declares said opaque
// 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;
}
@ -148,7 +154,12 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
// If we know that all values of the return type are structurally matchable, there's no
// need to run dataflow.
_ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false,
// Opaque types do not participate in const generics or pattern matching, so we can safely count them out.
_ 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(_) => {
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)

View File

@ -79,7 +79,6 @@ pub fn equal_up_to_regions<'tcx>(
}
// Normalize lifetimes away on both sides, then compare.
let param_env = param_env.with_reveal_all_normalized(tcx);
let normalize = |ty: Ty<'tcx>| {
tcx.normalize_erasing_regions(
param_env,
@ -170,9 +169,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// Equal types, all is good.
return true;
}
// Normalization reveals opaque types, but we may be validating MIR while computing
// said opaque types, causing cycles.
if (src, dest).has_opaque_types() {
return true;
}
// Normalize projections and things like that.
// 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 dest = self.tcx.normalize_erasing_regions(param_env, dest);

View File

@ -30,6 +30,11 @@ 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.
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
@ -39,6 +44,15 @@ where
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.
///
/// The supplied predicate will be applied to each (key, value) pair and it will return a
@ -58,7 +72,7 @@ where
// This should return just one element, otherwise it's a bug
assert!(
filter.next().is_none(),
"Collection {:?} should have just one matching element",
"Collection {:#?} should have just one matching element",
self
);
Some(value)

View File

@ -34,6 +34,12 @@ pub struct At<'a, 'tcx> {
pub infcx: &'a InferCtxt<'a, 'tcx>,
pub cause: &'a ObligationCause<'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> {
@ -49,7 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> At<'a, 'tcx> {
At { infcx: self, cause, param_env }
At { infcx: self, cause, param_env, define_opaque_types: true }
}
/// Forks the inference context, creating a new inference context with the same inference
@ -59,6 +65,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Self {
tcx: self.tcx.clone(),
defining_use_anchor: self.defining_use_anchor.clone(),
reveal_defining_opaque_types: self.reveal_defining_opaque_types.clone(),
in_progress_typeck_results: self.in_progress_typeck_results.clone(),
inner: self.inner.clone(),
skip_leak_check: self.skip_leak_check.clone(),
@ -86,6 +93,10 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
}
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.
pub fn eq_impl_headers(
self,
@ -216,7 +227,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
fields
.sub(a_is_expected)
.relate(a, b)
@ -233,7 +244,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
fields
.equate(a_is_expected)
.relate(a, b)
@ -248,7 +259,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
fields
.lub(a_is_expected)
.relate(a, b)
@ -263,7 +274,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
fields
.glb(a_is_expected)
.relate(a, b)

View File

@ -22,10 +22,12 @@ use rustc_data_structures::captures::Captures;
use rustc_index::vec::Idx;
use rustc_index::vec::IndexVec;
use rustc_middle::arena::ArenaAllocatable;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt};
use rustc_span::Span;
use std::fmt::Debug;
use std::iter;
@ -89,6 +91,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
var_values: inference_vars,
region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Proven, // Ambiguities are OK!
opaque_types: vec![],
value: answer,
})
}
@ -133,14 +136,27 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
let certainty =
if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
let opaque_types = self.take_opaque_types_for_query_response();
Ok(QueryResponse {
var_values: inference_vars,
region_constraints,
certainty,
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,
/// instantiates the result so it can be used, plugging in the
/// values from the canonical query. (Note that the result may
@ -223,13 +239,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
where
R: Debug + TypeFoldable<'tcx>,
{
let result_subst =
self.query_response_substitution_guess(cause, original_values, query_response);
let InferOk { value: result_subst, mut obligations } = self
.query_response_substitution_guess(cause, param_env, original_values, query_response)?;
// Compute `QueryOutlivesConstraint` values that unify each of
// the original values `v_o` that was canonicalized into a
// variable...
let mut obligations = vec![];
for (index, original_value) in original_values.var_values.iter().enumerate() {
// ...with the value `v_r` of that variable from the query.
@ -343,20 +358,25 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
original_values, query_response,
);
let result_subst =
self.query_response_substitution_guess(cause, original_values, query_response);
let mut value = self.query_response_substitution_guess(
cause,
param_env,
original_values,
query_response,
)?;
let obligations = self
.unify_query_response_substitution_guess(
value.obligations.extend(
self.unify_query_response_substitution_guess(
cause,
param_env,
original_values,
&result_subst,
&value.value,
query_response,
)?
.into_obligations();
.into_obligations(),
);
Ok(InferOk { value: result_subst, obligations })
Ok(value)
}
/// Given the original values and the (canonicalized) result from
@ -371,9 +391,10 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
fn query_response_substitution_guess<R>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
original_values: &OriginalQueryValues<'tcx>,
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
) -> CanonicalVarValues<'tcx>
) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
where
R: Debug + TypeFoldable<'tcx>,
{
@ -473,7 +494,16 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
.collect(),
};
result_subst
let mut obligations = vec![];
// 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, true, cause, param_env)?.obligations);
}
Ok(InferOk { value: result_subst, obligations })
}
/// Given a "guess" at the values for the canonical variables in
@ -629,6 +659,10 @@ struct QueryTypeRelatingDelegate<'a, 'tcx> {
}
impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
fn span(&self) -> Span {
self.cause.span
}
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
@ -684,4 +718,18 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
fn forbid_inference_vars() -> bool {
true
}
fn register_opaque_type(
&mut self,
a: Ty<'tcx>,
b: Ty<'tcx>,
a_is_expected: bool,
) -> Result<(), TypeError<'tcx>> {
self.obligations.extend(
self.infcx
.handle_opaque_type(a, b, a_is_expected, &self.cause, self.param_env)?
.obligations,
);
Ok(())
}
}

View File

@ -51,6 +51,12 @@ pub struct CombineFields<'infcx, 'tcx> {
pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'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)]
@ -322,6 +328,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
/// will first instantiate `b_vid` with a *generalized* version
/// of `a_ty`. Generalization introduces other inference
/// variables wherever subtyping could occur.
#[instrument(skip(self), level = "debug")]
pub fn instantiate(
&mut self,
a_ty: Ty<'tcx>,
@ -334,8 +341,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
// 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!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid);
// Generalize type of `a_ty` appropriately depending on the
// direction. As an example, assume:
//
@ -348,10 +353,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
// variables. (Down below, we will relate `a_ty <: b_ty`,
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
debug!(
"instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})",
a_ty, dir, b_vid, b_ty
);
debug!(?b_ty);
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
if needs_wf {
@ -392,13 +394,13 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
/// Preconditions:
///
/// - `for_vid` is a "root vid"
#[instrument(skip(self), level = "trace")]
fn generalize(
&self,
ty: Ty<'tcx>,
for_vid: ty::TyVid,
dir: RelationDir,
) -> RelateResult<'tcx, Generalization<'tcx>> {
debug!("generalize(ty={:?}, for_vid={:?}, dir={:?}", ty, for_vid, dir);
// Determine the ambient variance within which `ty` appears.
// The surrounding equation is:
//
@ -412,7 +414,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
RelationDir::SupertypeOf => ty::Contravariant,
};
debug!("generalize: ambient_variance = {:?}", ambient_variance);
trace!(?ambient_variance);
let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
v @ TypeVariableValue::Known { .. } => {
@ -421,8 +423,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
TypeVariableValue::Unknown { universe } => universe,
};
debug!("generalize: for_universe = {:?}", for_universe);
debug!("generalize: trace = {:?}", self.trace);
trace!(?for_universe);
trace!(?self.trace);
let mut generalize = Generalizer {
infcx: self.infcx,
@ -439,12 +441,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
let ty = match generalize.relate(ty, ty) {
Ok(ty) => ty,
Err(e) => {
debug!("generalize: failure {:?}", e);
debug!(?e, "failure");
return Err(e);
}
};
let needs_wf = generalize.needs_wf;
debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf);
trace!(?ty, ?needs_wf, "success");
Ok(Generalization { ty, needs_wf })
}

View File

@ -66,18 +66,19 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
self.relate(a, b)
}
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
trace!(a = ?a.kind(), b = ?b.kind());
let infcx = self.fields.infcx;
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b);
match (a.kind(), b.kind()) {
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
@ -91,6 +92,25 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
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.extend(
infcx
.handle_opaque_type(
a,
b,
self.a_is_expected(),
&self.fields.trace.cause,
self.param_env(),
)?
.obligations,
);
}
_ => {
self.fields.infcx.super_combine_tys(self, a, b)?;
}

View File

@ -6,7 +6,7 @@ use super::InferCtxt;
use super::Subtype;
use crate::infer::combine::ConstEquateRelation;
use crate::traits::ObligationCause;
use crate::traits::{ObligationCause, PredicateObligation};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Ty, TyCtxt};
@ -113,12 +113,20 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
&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, ()> {
let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(v, a)?;
sub.relate(v, b)?;
Ok(())
}
fn define_opaque_types(&self) -> bool {
self.fields.define_opaque_types
}
}
impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {

View File

@ -20,7 +20,7 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferCtxt;
use crate::traits::ObligationCause;
use crate::traits::{ObligationCause, PredicateObligation};
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
use rustc_middle::ty::TyVar;
use rustc_middle::ty::{self, Ty};
@ -35,6 +35,10 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'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
// the LUB/GLB of `a` and `b` as appropriate.
//
@ -45,6 +49,7 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
}
/// Relates two types using a given lattice.
#[instrument(skip(this), level = "debug")]
pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
this: &mut L,
a: Ty<'tcx>,
@ -53,15 +58,17 @@ pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
where
L: LatticeDir<'a, 'tcx>,
{
debug!("{}.lattice_tys({:?}, {:?})", this.tag(), a, b);
debug!("{}", this.tag());
if a == b {
return Ok(a);
}
let infcx = this.infcx();
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
match (a.kind(), b.kind()) {
// If one side is known to be a variable and one is not,
// create a variable (`v`) to represent the LUB. Make sure to
@ -98,6 +105,20 @@ where
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(
infcx
.handle_opaque_type(a, b, this.a_is_expected(), this.cause(), this.param_env())?
.obligations,
);
Ok(a)
}
_ => infcx.super_combine_tys(this, a, b),
}
}

View File

@ -6,7 +6,7 @@ use super::InferCtxt;
use super::Subtype;
use crate::infer::combine::ConstEquateRelation;
use crate::traits::ObligationCause;
use crate::traits::{ObligationCause, PredicateObligation};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Ty, TyCtxt};
@ -119,10 +119,18 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
&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, ()> {
let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(a, v)?;
sub.relate(b, v)?;
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::ValuePairs::*;
use self::opaque_types::OpaqueTypeMap;
use self::opaque_types::OpaqueTypeStorage;
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
@ -191,18 +191,8 @@ pub struct InferCtxtInner<'tcx> {
undo_log: InferCtxtUndoLogs<'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 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>>,
/// Caches for opaque type inference.
pub opaque_type_storage: OpaqueTypeStorage<'tcx>,
}
impl<'tcx> InferCtxtInner<'tcx> {
@ -216,8 +206,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
float_unification_storage: ut::UnificationTableStorage::new(),
region_constraint_storage: Some(RegionConstraintStorage::new()),
region_obligations: vec![],
opaque_types: Default::default(),
opaque_types_vars: Default::default(),
opaque_type_storage: Default::default(),
}
}
@ -236,6 +225,11 @@ impl<'tcx> InferCtxtInner<'tcx> {
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]
fn int_unification_table(
&mut self,
@ -296,6 +290,10 @@ pub struct InferCtxt<'a, 'tcx> {
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
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`
/// contains a reference to the typeck results being built up, which are
/// used for reading closure kinds/signatures as they are inferred,
@ -571,6 +569,7 @@ pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
defining_use_anchor: Option<LocalDefId>,
reveal_defining_opaque_types: bool,
}
pub trait TyCtxtInferExt<'tcx> {
@ -579,7 +578,12 @@ pub trait TyCtxtInferExt<'tcx> {
impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
InferCtxtBuilder {
tcx: self,
defining_use_anchor: None,
fresh_typeck_results: None,
reveal_defining_opaque_types: false,
}
}
}
@ -603,6 +607,13 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
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
/// inference context that contains each of the bound values
/// within instantiated as a fresh variable. The `f` closure is
@ -627,11 +638,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
}
pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
let InferCtxtBuilder {
tcx,
defining_use_anchor,
reveal_defining_opaque_types,
ref fresh_typeck_results,
} = *self;
let in_progress_typeck_results = fresh_typeck_results.as_ref();
f(InferCtxt {
tcx,
defining_use_anchor,
reveal_defining_opaque_types,
in_progress_typeck_results,
inner: RefCell::new(InferCtxtInner::new()),
lexical_region_resolutions: RefCell::new(None),
@ -766,6 +783,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
&'a self,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
define_opaque_types: bool,
) -> CombineFields<'a, 'tcx> {
CombineFields {
infcx: self,
@ -773,6 +791,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
cause: None,
param_env,
obligations: PredicateObligations::new(),
define_opaque_types,
}
}
@ -1088,12 +1107,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
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(
&self,
origin: TypeVariableOrigin,
universe: ty::UniverseIndex,
) -> Ty<'tcx> {
let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin);
let vid = self.next_ty_var_id_in_universe(origin, universe);
self.tcx.mk_ty_var(vid)
}

View File

@ -24,11 +24,13 @@
use crate::infer::combine::ConstEquateRelation;
use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue};
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
use rustc_span::Span;
use std::fmt::Debug;
use std::ops::ControlFlow;
@ -75,6 +77,7 @@ where
pub trait TypeRelatingDelegate<'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx>;
fn span(&self) -> Span;
/// Push a constraint `sup: sub` -- this constraint must be
/// satisfied for the two types to be related. `sub` and `sup` may
@ -88,6 +91,12 @@ pub trait TypeRelatingDelegate<'tcx> {
);
fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
fn register_opaque_type(
&mut self,
a: Ty<'tcx>,
b: Ty<'tcx>,
a_is_expected: bool,
) -> Result<(), TypeError<'tcx>>;
/// Creates a new universe index. Used when instantiating placeholders.
fn create_next_universe(&mut self) -> ty::UniverseIndex;
@ -277,7 +286,6 @@ where
projection_ty: ty::ProjectionTy<'tcx>,
value_ty: Ty<'tcx>,
) -> Ty<'tcx> {
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_span::DUMMY_SP;
match *value_ty.kind() {
@ -286,6 +294,8 @@ where
kind: TypeVariableOriginKind::MiscVariable,
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(other_projection_ty, var);
var
@ -531,6 +541,8 @@ where
#[instrument(skip(self), level = "debug")]
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);
if !D::forbid_inference_vars() {
@ -559,6 +571,35 @@ where
(&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), _)
if D::normalization() == NormalizationStrategy::Lazy =>
{

View File

@ -1,102 +1,196 @@
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk};
use crate::traits;
use hir::def_id::{DefId, LocalDefId};
use hir::{HirId, OpaqueTyOrigin};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_middle::ty::{
self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor,
};
use rustc_span::Span;
use std::ops::ControlFlow;
pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
mod table;
pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferResult;
/// Information about the opaque types whose values we
/// are inferring in this function (these are the `impl Trait` that
/// appear in the return type).
#[derive(Copy, Clone, Debug)]
#[derive(Clone, Debug)]
pub struct OpaqueTypeDecl<'tcx> {
/// The opaque type (`ty::Opaque`) for this declaration.
pub opaque_type: Ty<'tcx>,
/// The span of this particular definition of the opaque type. So
/// for example:
///
/// ```ignore (incomplete snippet)
/// type Foo = impl Baz;
/// fn bar() -> Foo {
/// // ^^^ This is the span we are looking for!
/// }
/// ```
///
/// In cases where the fn returns `(impl Trait, impl Trait)` or
/// other such combinations, the result is currently
/// over-approximated, but better than nothing.
pub definition_span: Span,
/// The type variable that represents the value of the opaque type
/// that we require. In other words, after we compile this function,
/// we will be created a constraint like:
///
/// Foo<'a, T> = ?C
///
/// where `?C` is the value of this type variable. =) It may
/// naturally refer to the type and lifetime parameters in scope
/// in this function, though ultimately it should only reference
/// those that are arguments to `Foo` in the constraint above. (In
/// other words, `?C` should not include `'b`, even though it's a
/// lifetime parameter on `foo`.)
pub concrete_ty: Ty<'tcx>,
/// The hidden types that have been inferred for this opaque type.
/// There can be multiple, but they are all `lub`ed together at the end
/// to obtain the canonical hidden type.
pub hidden_type: OpaqueHiddenType<'tcx>,
/// The origin of the opaque type.
pub origin: hir::OpaqueTyOrigin,
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// 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>>(
/// This is a backwards compatibility hack to prevent breaking changes from
/// lazy TAIT around RPIT handling.
pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>(
&self,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value: T,
value_span: Span,
body_id: HirId,
span: Span,
param_env: ty::ParamEnv<'tcx>,
) -> InferOk<'tcx, T> {
debug!(
"instantiate_opaque_types(value={:?}, body_id={:?}, \
param_env={:?}, value_span={:?})",
value, body_id, param_env, value_span,
);
let mut instantiator =
Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
let value = instantiator.instantiate_opaque_types_in_map(value);
InferOk { value, obligations: instantiator.obligations }
if !value.has_opaque_types() {
return InferOk { value, obligations: vec![] };
}
let mut obligations = vec![];
let value = value.fold_with(&mut ty::fold::BottomUpFolder {
tcx: self.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.opaque_type_origin(def_id, span),
Some(OpaqueTyOrigin::FnReturn(..))
) =>
{
let span = if span.is_dummy() { self.tcx.def_span(def_id) } else { span };
let cause = ObligationCause::misc(span, body_id);
let ty_var = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span: cause.span,
});
obligations.extend(
self.handle_opaque_type(ty, ty_var, true, &cause, param_env)
.unwrap()
.obligations,
);
ty_var
}
_ => ty,
},
});
InferOk { value, obligations }
}
pub fn handle_opaque_type(
&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
a_is_expected: bool,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> InferResult<'tcx, ()> {
if a.references_error() || b.references_error() {
return Ok(InferOk { value: (), obligations: vec![] });
}
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
ty::Opaque(def_id, substs) => {
let origin = if self.defining_use_anchor.is_some() {
// 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)?
} else {
self.opaque_ty_origin_unchecked(def_id, cause.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
// want to make a decision on it right now. Likely this case is so super rare anyway, that
// no one encounters it in practice.
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
// 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,
origin,
))
}
_ => 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.kind(), b.kind())
),
Err(e) => Err(e),
}
}
}
/// Given the map `opaque_types` containing the opaque
@ -231,51 +325,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// but this is not necessary, because the opaque type we
/// create will be allowed to reference `T`. So we only generate 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))]
pub fn constrain_opaque_type(
pub fn register_member_constraints(
&self,
param_env: ty::ParamEnv<'tcx>,
opaque_type_key: OpaqueTypeKey<'tcx>,
opaque_defn: &OpaqueTypeDecl<'tcx>,
concrete_ty: Ty<'tcx>,
span: Span,
) {
let def_id = opaque_type_key.def_id;
let tcx = self.tcx;
let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
let concrete_ty = self.resolve_vars_if_possible(concrete_ty);
debug!(?concrete_ty);
let first_own_region = match opaque_defn.origin {
let first_own_region = match self.opaque_ty_origin_unchecked(def_id, span) {
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
// We lower
//
@ -319,7 +385,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
op: |r| {
self.member_constraint(
opaque_type_key.def_id,
opaque_defn.definition_span,
span,
concrete_ty,
r,
&choice_regions,
@ -328,15 +394,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
});
}
fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<hir::OpaqueTyOrigin> {
let tcx = self.tcx;
let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
#[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 item_kind = &tcx.hir().expect_item(def_id).kind;
let item_kind = &self.tcx.hir().expect_item(def_id).kind;
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
span_bug!(
tcx.def_span(def_id),
"weird opaque type: {:#?}",
span,
"weird opaque type: {:#?}, {:#?}",
opaque_def_id,
item_kind
)
};
@ -347,11 +416,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
// Named `type Foo = impl Bar;`
hir::OpaqueTyOrigin::TyAlias => {
may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
}
};
trace!(?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
}
}
// Visitor that requires that (almost) all regions in the type visited outlive
@ -426,180 +509,93 @@ where
}
}
struct Instantiator<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value_span: Span,
obligations: Vec<traits::PredicateObligation<'tcx>>,
pub enum UseKind {
DefiningUse,
OpaqueUse,
}
impl<'a, 'tcx> Instantiator<'a, 'tcx> {
fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
let tcx = self.infcx.tcx;
value.fold_with(&mut BottomUpFolder {
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,
})
}
#[instrument(skip(self), level = "debug")]
fn fold_opaque_ty(
&mut self,
ty: Ty<'tcx>,
opaque_type_key: OpaqueTypeKey<'tcx>,
origin: hir::OpaqueTyOrigin,
) -> Ty<'tcx> {
let infcx = self.infcx;
let tcx = infcx.tcx;
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;
impl UseKind {
pub fn is_defining(self) -> bool {
match self {
UseKind::DefiningUse => true,
UseKind::OpaqueUse => false,
}
}
}
let ty_var = infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span: self.value_span,
});
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
pub fn register_hidden_type(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
origin: hir::OpaqueTyOrigin,
) -> InferResult<'tcx, ()> {
let tcx = self.tcx;
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
// Ideally, we'd get the span where *this specific `ty` came
// from*, but right now we just use the span from the overall
// value being folded. In simple cases like `-> impl Foo`,
// these are the same span, but not in cases like `-> (impl
// Foo, impl Bar)`.
let definition_span = self.value_span;
let span = cause.span;
{
let mut infcx = self.infcx.inner.borrow_mut();
infcx.opaque_types.insert(
OpaqueTypeKey { def_id, substs },
OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
);
infcx.opaque_types_vars.insert(ty_var, ty);
let mut obligations = vec![];
let prev = self.inner.borrow_mut().opaque_types().register(
OpaqueTypeKey { def_id, substs },
OpaqueHiddenType { ty: hidden_ty, span },
origin,
);
if let Some(prev) = prev {
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);
self.obligations.reserve(item_bounds.len());
for (predicate, _) in item_bounds {
debug!(?predicate);
let predicate = predicate.subst(tcx, substs);
debug!(?predicate);
let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx,
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,
// as the bounds must hold on the hidden type after all.
ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => {
ty_var
}
// Instantiate nested instances of `impl Trait`.
ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty),
_ => ty,
},
lt_op: |lt| lt,
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,
)
hidden_ty
}
_ => ty,
},
lt_op: |lt| lt,
ct_op: |ct| ct,
});
debug!(?predicate);
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
if projection.term.references_error() {
return tcx.ty_error();
// No point on adding these obligations since there's a type error involved.
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.
debug!(?predicate);
self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
obligations.push(traits::Obligation::new(cause.clone(), param_env, predicate));
}
ty_var
Ok(InferOk { value: (), obligations })
}
}

View File

@ -0,0 +1,80 @@
use rustc_data_structures::undo_log::UndoLogs;
use rustc_hir::OpaqueTyOrigin;
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
use rustc_span::DUMMY_SP;
use crate::infer::{InferCtxtUndoLogs, UndoLog};
use super::{OpaqueTypeDecl, OpaqueTypeMap};
#[derive(Default, Debug, Clone)]
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(_) => {}
}
}
}
#[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(crate) 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

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

View File

@ -2,6 +2,7 @@ use super::combine::{CombineFields, RelationDir};
use super::SubregionOrigin;
use crate::infer::combine::ConstEquateRelation;
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::traits::Obligation;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
@ -74,9 +75,8 @@ 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>> {
debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
@ -84,6 +84,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
let infcx = self.fields.infcx;
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
match (a.kind(), b.kind()) {
(&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
// Shouldn't have any LBR here, so we can safely put
@ -121,6 +122,38 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
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.extend(
infcx
.handle_opaque_type(a, b, true, &self.fields.trace.cause, self.param_env())?
.obligations,
);
Ok(a)
}
_ => {
self.fields.infcx.super_combine_tys(self, a, b)?;
Ok(a)

View File

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

View File

@ -178,6 +178,12 @@ pub struct QueryResponse<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: QueryRegionConstraints<'tcx>,
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,
}

View File

@ -1,7 +1,7 @@
//! Values computed by queries that use MIR.
use crate::mir::{Body, Promoted};
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
use rustc_data_structures::stable_map::FxHashMap;
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorGuaranteed;
@ -242,7 +242,7 @@ pub struct BorrowCheckResult<'tcx> {
/// All the opaque types that are restricted to concrete types
/// by this function. Unlike the value in `TypeckResults`, this has
/// unerased regions.
pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
pub used_mut_upvars: SmallVec<[Field; 8]>,
pub tainted_by_errors: Option<ErrorGuaranteed>,

View File

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

View File

@ -33,6 +33,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@ -485,9 +486,13 @@ pub struct TypeckResults<'tcx> {
/// this field will be set to `Some(ErrorGuaranteed)`.
pub tainted_by_errors: Option<ErrorGuaranteed>,
/// All the opaque types that are restricted to concrete types
/// by this function.
pub concrete_opaque_types: FxHashSet<DefId>,
/// All the opaque types that have hidden types set
/// by this function. For return-position-impl-trait we also store the
/// type here, so that mir-borrowck can figure out hidden types,
/// 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;
/// see `MinCaptureInformationMap` for more details.

View File

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

View File

@ -1057,12 +1057,55 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, TypeFoldable)]
#[derive(
Copy,
Clone,
Debug,
PartialEq,
Eq,
HashStable,
TyEncodable,
TyDecodable,
TypeFoldable,
Lift
)]
pub struct OpaqueTypeKey<'tcx> {
pub def_id: DefId,
pub substs: SubstsRef<'tcx>,
}
#[derive(Copy, Clone, Debug, TypeFoldable, HashStable, TyEncodable, TyDecodable)]
pub struct OpaqueHiddenType<'tcx> {
/// The span of this particular definition of the opaque type. So
/// for example:
///
/// ```ignore (incomplete snippet)
/// type Foo = impl Baz;
/// fn bar() -> Foo {
/// // ^^^ This is the span we are looking for!
/// }
/// ```
///
/// In cases where the fn returns `(impl Trait, impl Trait)` or
/// other such combinations, the result is currently
/// over-approximated, but better than nothing.
pub span: Span,
/// The type variable that represents the value of the opaque type
/// that we require. In other words, after we compile this function,
/// we will be created a constraint like:
///
/// Foo<'a, T> = ?C
///
/// where `?C` is the value of this type variable. =) It may
/// naturally refer to the type and lifetime parameters in scope
/// in this function, though ultimately it should only reference
/// those that are arguments to `Foo` in the constraint above. (In
/// other words, `?C` should not include `'b`, even though it's a
/// lifetime parameter on `foo`.)
pub ty: Ty<'tcx>,
}
rustc_index::newtype_index! {
/// "Universes" are used during type- and trait-checking in the
/// presence of `for<..>` binders to control what sets of names are

View File

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

View File

@ -1925,6 +1925,13 @@ impl<'tcx> Ty<'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>) {
match self.kind() {
Adt(def, substs) => {

View File

@ -1,8 +1,8 @@
use crate::build::matches::ArmHasGuard;
use crate::build::ForGuard::OutsideGuard;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::{mir::*, ty};
use rustc_span::Span;
impl<'a, 'tcx> Builder<'a, 'tcx> {
@ -190,7 +190,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// 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
// the case of `!`, no return value is required, as the block will never return.
if destination_ty.is_unit() {
// Opaque types of empty bodies also need this unit assignment, in order to infer that their
// 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
// 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);

View File

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

View File

@ -5,15 +5,14 @@ use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt};
use rustc_span::Span;
pub trait InferCtxtExt<'tcx> {
fn infer_opaque_definition_from_instantiation(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: Ty<'tcx>,
span: Span,
instantiated_ty: OpaqueHiddenType<'tcx>,
) -> Ty<'tcx>;
}
@ -33,7 +32,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
/// purpose of this function is to do that translation.
///
/// (*) C1 and C2 were introduced in the comments on
/// `constrain_opaque_type`. Read that comment for more context.
/// `register_member_constraints`. Read that comment for more context.
///
/// # Parameters
///
@ -45,9 +44,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
fn infer_opaque_definition_from_instantiation(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: Ty<'tcx>,
span: Span,
instantiated_ty: OpaqueHiddenType<'tcx>,
) -> Ty<'tcx> {
if self.is_tainted_by_errors() {
return self.tcx.ty_error();
}
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
// Use substs to build up a reverse map from regions to their
@ -65,13 +67,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
// after producing an error for each of them.
let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new(
let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
self.tcx,
self.is_tainted_by_errors(),
def_id,
map,
instantiated_ty,
span,
instantiated_ty.ty,
instantiated_ty.span,
));
debug!(?definition_ty);
@ -82,10 +83,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
struct ReverseMapper<'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,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
map_missing_regions_to_empty: bool,
@ -100,7 +97,6 @@ struct ReverseMapper<'tcx> {
impl<'tcx> ReverseMapper<'tcx> {
fn new(
tcx: TyCtxt<'tcx>,
tainted_by_errors: bool,
opaque_type_def_id: DefId,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
hidden_ty: Ty<'tcx>,
@ -108,7 +104,6 @@ impl<'tcx> ReverseMapper<'tcx> {
) -> Self {
Self {
tcx,
tainted_by_errors,
opaque_type_def_id,
map,
map_missing_regions_to_empty: false,
@ -167,9 +162,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
match self.map.get(&r.into()).map(|k| k.unpack()) {
Some(GenericArgKind::Lifetime(r1)) => r1,
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
None if self.map_missing_regions_to_empty || self.tainted_by_errors => {
self.tcx.lifetimes.re_root_empty
}
None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
None if generics.parent.is_some() => {
if let Some(hidden_ty) = self.hidden_ty.take() {
unexpected_hidden_region_diagnostic(

View File

@ -92,6 +92,12 @@ pub fn codegen_fulfill_obligation<'tcx>(
});
let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
// There should be no opaque types during codegen, they all get revealed.
let opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
if !opaque_types.is_empty() {
bug!("{:#?}", opaque_types);
}
debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
Ok(&*tcx.arena.alloc(impl_source))
})

View File

@ -1294,6 +1294,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
ty::Generator(..) => "generator",
_ => "function",
};
let span = self.tcx.sess.source_map().guess_head_span(span);
let mut err = struct_span_err!(
self.tcx.sess,
span,
@ -1673,6 +1674,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
));
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 message = outer_generator

View File

@ -214,10 +214,21 @@ fn project_and_unify_type<'cx, 'tcx>(
Err(InProgress) => return Ok(Err(InProgress)),
};
debug!(?normalized, ?obligations, "project_and_unify_type result");
match infcx
.at(&obligation.cause, obligation.param_env)
.eq(normalized, obligation.predicate.term)
{
let actual = obligation.predicate.term;
// HACK: lazy TAIT would regress src/test/ui/impl-trait/nested-return-type2.rs, so we add
// a back-compat hack hat converts the RPITs into inference vars, just like they were before
// lazy TAIT.
// This does not affect TAITs in general, as tested in the nested-return-type-tait* tests.
let InferOk { value: actual, obligations: new } =
selcx.infcx().replace_opaque_types_with_inference_vars(
actual,
obligation.cause.body_id,
obligation.cause.span,
obligation.param_env,
);
obligations.extend(new);
match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
Ok(Ok(Some(obligations)))

View File

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

View File

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

View File

@ -256,6 +256,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};
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>`).
//
// This is somewhat problematic, as the current scheme can't really

View File

@ -33,6 +33,7 @@ use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::fast_reject::{self, TreatParams};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
@ -1313,6 +1314,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
#[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")]
fn insert_candidate_cache(
&mut self,
mut param_env: ty::ParamEnv<'tcx>,
@ -1353,6 +1355,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// 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
/// `tcx.item_bounds` for any applicable bounds.
#[instrument(level = "debug", skip(self))]
fn match_projection_obligation_against_definition_bounds(
&mut self,
obligation: &TraitObligation<'tcx>,
@ -1360,10 +1363,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
let placeholder_trait_predicate =
self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
debug!(
?placeholder_trait_predicate,
"match_projection_obligation_against_definition_bounds"
);
debug!(?placeholder_trait_predicate);
let tcx = self.infcx.tcx;
let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
@ -1414,7 +1414,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
})
.collect();
debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds");
debug!(?matching_bounds);
matching_bounds
}
@ -1444,6 +1444,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
});
self.infcx
.at(&obligation.cause, obligation.param_env)
.define_opaque_types(false)
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
.map(|InferOk { obligations: _, value: () }| {
// This method is called within a probe, so we can't have
@ -1506,6 +1507,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let is_match = self
.infcx
.at(&obligation.cause, obligation.param_env)
.define_opaque_types(false)
.sup(obligation.predicate, infer_projection)
.map_or(false, |InferOk { obligations, value: () }| {
self.evaluate_predicates_recursively(
@ -2081,11 +2083,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match self.match_impl(impl_def_id, obligation) {
Ok(substs) => substs,
Err(()) => {
bug!(
"Impl {:?} was matchable against {:?} but now is not",
impl_def_id,
obligation
self.infcx.tcx.sess.delay_span_bug(
obligation.cause.span,
&format!(
"Impl {:?} was matchable against {:?} but now is not",
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![] }
}
}
}
@ -2137,6 +2150,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.at(&cause, obligation.param_env)
.define_opaque_types(false)
.eq(placeholder_obligation_trait_ref, impl_trait_ref)
.map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
nested_obligations.extend(obligations);
@ -2220,6 +2234,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
self.infcx
.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)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| ())

View File

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

View File

@ -61,6 +61,14 @@ bitflags! {
| TypeFlags::HAS_CT_INFER.bits
| TypeFlags::HAS_TY_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
// to depend on a particular fn.
// The freshening process throws away information,

View File

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

View File

@ -538,7 +538,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Expectation<'tcx>,
fn_sig: ty::FnSig<'tcx>,
) -> Ty<'tcx> {
// `fn_sig` is the *signature* of the cosure being called. We
// `fn_sig` is the *signature* of the closure being called. 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
// type.

View File

@ -17,7 +17,7 @@ use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, Ty, TyCtxt};
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_span::symbol::sym;
use rustc_span::{self, MultiSpan, Span};
@ -83,8 +83,6 @@ pub(super) fn check_fn<'a, 'tcx>(
can_be_generator: Option<hir::Movability>,
return_type_pre_known: bool,
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
let mut fn_sig = fn_sig;
// Create the function context. This is either derived from scratch or,
// in the case of closures, based on the outer context.
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
@ -97,21 +95,15 @@ pub(super) fn check_fn<'a, 'tcx>(
let declared_ret_ty = fn_sig.output();
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)));
let ret_ty =
fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
declared_ret_ty,
body.value.hir_id,
DUMMY_SP,
param_env,
));
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
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;
@ -253,7 +245,7 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
}
fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
fcx.demand_suptype(span, declared_ret_ty, actual_return_ty);
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
@ -656,6 +648,8 @@ fn check_opaque_meets_bounds<'tcx>(
span: Span,
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 defining_use_anchor = match *origin {
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
@ -670,25 +664,13 @@ fn check_opaque_meets_bounds<'tcx>(
let misc_cause = traits::ObligationCause::misc(span, hir_id);
let _ = inh.register_infer_ok_obligations(
infcx.instantiate_opaque_types(hir_id, param_env, opaque_ty, span),
);
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,
),
);
}
match infcx.at(&misc_cause, param_env).eq(opaque_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 unify `{}` with revealed type:\n{}", hidden_type, ty_err,),
);
}
}
@ -701,7 +683,7 @@ fn check_opaque_meets_bounds<'tcx>(
match origin {
// Checked when type checking the function containing them.
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
// Can have different predicates to their defining use
hir::OpaqueTyOrigin::TyAlias => {
// Finally, resolve all regions. This catches wily misuses of
@ -710,6 +692,9 @@ fn check_opaque_meets_bounds<'tcx>(
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,6 +3,7 @@
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
use crate::astconv::AstConv;
use crate::rustc_middle::ty::subst::Subst;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
@ -13,6 +14,7 @@ use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
use rustc_span::DUMMY_SP;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::ArgKind;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
@ -172,6 +174,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty: Ty<'tcx>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
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, ..) => {
let sig = object_type.projection_bounds().find_map(|pb| {
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
@ -197,10 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
let expected_sig =
self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
debug!(
"deduce_expectations_from_obligations: obligation.predicate={:?}",
obligation.predicate
);
debug!(?obligation.predicate);
let bound_predicate = obligation.predicate.kind();
if let ty::PredicateKind::Projection(proj_predicate) =
@ -235,6 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// The `cause_span` should be the span that caused us to
/// have this expected signature, or `None` if we can't readily
/// know that.
#[instrument(level = "debug", skip(self, cause_span))]
fn deduce_sig_from_projection(
&self,
cause_span: Option<Span>,
@ -242,15 +265,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Option<ExpectedSig<'tcx>> {
let tcx = self.tcx;
debug!("deduce_sig_from_projection({:?})", projection);
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 gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
let is_gen = gen_trait == trait_def_id;
if !is_fn && !is_gen {
debug!("deduce_sig_from_projection: not fn or generator");
debug!("not fn or generator");
return None;
}
@ -259,7 +280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// associated item and not yield.
let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1];
if return_assoc_item != projection.projection_def_id() {
debug!("deduce_sig_from_projection: not return assoc item of generator");
debug!("not return assoc item of generator");
return None;
}
}
@ -267,7 +288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let input_tys = if is_fn {
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);
debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
debug!(?arg_param_ty);
match arg_param_ty.kind() {
&ty::Tuple(tys) => tys,
@ -282,7 +303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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 = self.resolve_vars_if_possible(ret_param_ty);
debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
debug!(?ret_param_ty);
let sig = projection.rebind(self.tcx.mk_fn_sig(
input_tys.iter(),
@ -291,7 +312,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::Unsafety::Normal,
Abi::Rust,
));
debug!("deduce_sig_from_projection: sig={:?}", sig);
debug!(?sig);
Some(ExpectedSig { cause_span, sig })
}
@ -401,9 +422,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// in this binder we are creating.
assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST));
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(
sig.inputs().iter().cloned(),
sig.output(),
output,
sig.c_variadic,
hir::Unsafety::Normal,
Abi::RustCall,
@ -590,6 +616,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => 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(
self.tcx.mk_fn_sig(
@ -610,27 +638,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
result
}
fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
let InferOk { value, obligations } =
self.replace_opaque_types_with_inference_vars(ty, body_id, span, self.param_env);
self.register_predicates(obligations);
value
}
/// Invoked when we are translating the generator that results
/// from desugaring an `async fn`. Returns the "sugared" return
/// type of the `async fn` -- that is, the return type that the
/// user specified. The "desugared" return type is an `impl
/// Future<Output = T>`, so we do this by searching through the
/// obligations to extract the `T`.
#[instrument(skip(self), level = "debug")]
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(|| {
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 = self.inh.infcx.shallow_resolve(ret_ty);
let ret_vid = match *ret_ty.kind() {
ty::Infer(ty::TyVar(ret_vid)) => ret_vid,
let (def_id, substs) = match *ret_ty.kind() {
ty::Opaque(def_id, substs) => (def_id, substs),
ty::Error(_) => return None,
_ => span_bug!(
self.tcx.def_span(expr_def_id),
@ -638,17 +668,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
};
let item_bounds = self.tcx.explicit_item_bounds(def_id);
// Search for a pending obligation like
//
// `<R as Future>::Output = T`
//
// where R is the return type we are expecting. This type `T`
// will be our output.
let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
let bound_predicate = obligation.predicate.kind();
let output_ty = item_bounds.iter().find_map(|&(predicate, span)| {
let bound_predicate = predicate.subst(self.tcx, substs).kind();
if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
self.deduce_future_output_from_projection(
obligation.cause.span,
span,
bound_predicate.rebind(proj_predicate),
)
} else {

View File

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

View File

@ -965,8 +965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let else_diverges = self.diverges.get();
let opt_suggest_box_span =
self.opt_suggest_box_span(else_expr.span, else_ty, orig_expected);
let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected);
let if_cause =
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()
);
// Check if we have any unsolved varibales. If not, no need for fallback.
// Check if we have any unsolved variables. If not, no need for fallback.
let unsolved_variables = self.unsolved_variables();
if unsolved_variables.is_empty() {
return false;
@ -66,16 +66,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
// refer to opaque types.
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
}
@ -136,59 +126,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
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
/// a result of our need to balance 'do the right thing' with
/// backwards compatibility.

View File

@ -372,23 +372,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(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
/// 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
@ -775,6 +758,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Vec<Ty<'tcx>> {
let formal_ret = self.resolve_vars_with_obligations(formal_ret);
let Some(ret_ty) = expected_ret.only_has_type(self) else { return Vec::new() };
// HACK(oli-obk): This is a hack to keep RPIT and TAIT in sync wrt their behaviour.
// 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.
// See src/test/ui/impl-trait/hidden-type-is-opaque.rs and
// src/test/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path.
if formal_ret.has_infer_types() {
for ty in ret_ty.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();
}
}
}
}
}
let expect_args = self
.fudge_inference_if_ok(|| {
// Attempt to apply a subtyping relationship between the formal

View File

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

View File

@ -95,6 +95,13 @@ impl<'tcx> InheritedBuilder<'tcx> {
let def_id = self.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> {
@ -119,8 +126,8 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
}
}
#[instrument(level = "debug", skip(self))]
pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
debug!("register_predicate({:?})", obligation);
if obligation.has_escaping_bound_vars() {
span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
}

View File

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

View File

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

View File

@ -335,11 +335,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Returns a list of `Ty`s for each upvar.
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
.borrow()
.closure_min_captures_flattened(closure_id)

View File

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

View File

@ -18,9 +18,9 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::opaque_types::InferCtxtExt;
use std::mem;
use std::ops::ControlFlow;
///////////////////////////////////////////////////////////////////////////
// Entry point
@ -65,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types();
wbcx.visit_opaque_types(body.value.span);
wbcx.visit_opaque_types();
wbcx.visit_coercion_casts();
wbcx.visit_user_provided_tys();
wbcx.visit_user_provided_sigs();
@ -497,64 +497,39 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fcx_typeck_results.generator_interior_types.clone();
}
#[instrument(skip(self, span), level = "debug")]
fn visit_opaque_types(&mut self, span: Span) {
let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone();
for (opaque_type_key, opaque_defn) in opaque_types {
let hir_id =
self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local());
let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
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;
#[instrument(skip(self), level = "debug")]
fn visit_opaque_types(&mut self) {
let opaque_types =
self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
for (opaque_type_key, decl) in opaque_types {
let hidden_type = match decl.origin {
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
let ty = self.resolve(decl.hidden_type.ty, &decl.hidden_type.span);
struct RecursionChecker {
def_id: DefId,
}
impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
type BreakTy = ();
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::Opaque(def_id, _) = *t.kind() {
if def_id == self.def_id {
return ControlFlow::Break(());
}
}
t.super_visit_with(self)
}
}
if ty
.visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
.is_break()
{
return;
}
Some(ty)
}
}
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);
}
hir::OpaqueTyOrigin::TyAlias => None,
};
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
}
}

View File

@ -8,7 +8,7 @@ use rustc_hir::{HirId, Node};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder};
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
@ -358,29 +358,24 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
.concrete_opaque_types
.get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
.copied()
.map(|concrete| concrete.ty)
.unwrap_or_else(|| {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"owner {:?} has no opaque type for {:?} in its typeck results",
owner, def_id,
),
);
if let Some(_) =
tcx.typeck(owner).tainted_by_errors
{
let table = tcx.typeck(owner);
if let Some(_) = table.tainted_by_errors {
// Some error in the
// owner fn prevented us from populating
// the `concrete_opaque_types` table.
tcx.ty_error()
} else {
// We failed to resolve the opaque type or it
// resolves to itself. Return the non-revealed
// type, which should result in E0720.
tcx.mk_opaque(
def_id.to_def_id(),
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
)
table.concrete_opaque_types.get(&def_id.to_def_id()).copied().unwrap_or_else(|| {
// We failed to resolve the opaque type or it
// resolves to itself. We interpret this as the
// no values of the hidden type ever being constructed,
// so we can just make the hidden type be `!`.
// For backwards compatibility reasons, we fall back to
// `()` 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);
@ -562,7 +557,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
/// with the first type that we find, and then later types are
/// checked against it (we also carry the span of that first
/// type).
found: Option<(Span, Ty<'tcx>)>,
found: Option<ty::OpaqueHiddenType<'tcx>>,
}
impl ConstraintLocator<'_> {
@ -575,14 +570,28 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
}
// Calling `mir_borrowck` can lead to cycle errors through
// const-checking, avoid calling it if we don't have to.
if !self.tcx.typeck(def_id).concrete_opaque_types.contains(&self.def_id) {
// ```rust
// 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(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
return;
}
if tables.concrete_opaque_types.get(&self.def_id).is_none() {
debug!("no constraints in typeck results");
return;
}
// Use borrowck to get the type with unerased regions.
let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
debug!(?concrete_opaque_types);
for (opaque_type_key, concrete_type) in concrete_opaque_types {
for &(opaque_type_key, concrete_type) in concrete_opaque_types {
if opaque_type_key.def_id != self.def_id {
// Ignore constraints for other opaque types.
continue;
@ -590,26 +599,26 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
debug!(?concrete_type, ?opaque_type_key.substs, "found constraint");
// FIXME(oli-obk): trace the actual span from inference to improve errors.
let span = self.tcx.def_span(def_id);
if let Some((prev_span, prev_ty)) = self.found {
if *concrete_type != prev_ty && !(*concrete_type, prev_ty).references_error() {
debug!(?span);
if let Some(prev) = self.found {
if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() {
// Found different concrete types for the opaque type.
let mut err = self.tcx.sess.struct_span_err(
span,
concrete_type.span,
"concrete type differs from previous defining opaque type use",
);
err.span_label(
span,
format!("expected `{}`, got `{}`", prev_ty, concrete_type),
concrete_type.span,
format!("expected `{}`, got `{}`", prev.ty, concrete_type.ty),
);
err.span_note(prev_span, "previous use here");
if prev.span == concrete_type.span {
err.span_label(prev.span, "this expression supplies two conflicting concrete types for the same opaque type");
} else {
err.span_note(prev.span, "previous use here");
}
err.emit();
}
} else {
self.found = Some((span, *concrete_type));
self.found = Some(concrete_type);
}
}
}
@ -629,7 +638,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
debug!("find_existential_constraints: visiting {:?}", it);
trace!(?it.def_id);
// The opaque type itself or its children are not within its reveal scope.
if it.def_id.to_def_id() != self.def_id {
self.check(it.def_id);
@ -637,7 +646,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
}
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
debug!("find_existential_constraints: visiting {:?}", it);
trace!(?it.def_id);
// The opaque type itself or its children are not within its reveal scope.
if it.def_id.to_def_id() != self.def_id {
self.check(it.def_id);
@ -645,7 +654,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
}
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
debug!("find_existential_constraints: visiting {:?}", it);
trace!(?it.def_id);
self.check(it.def_id);
intravisit::walk_trait_item(self, it);
}
@ -655,12 +664,12 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
let scope = tcx.hir().get_defining_scope(hir_id);
let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None };
debug!("find_opaque_ty_constraints: scope={:?}", scope);
debug!(?scope);
if scope == hir::CRATE_HIR_ID {
tcx.hir().walk_toplevel_module(&mut locator);
} else {
debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
trace!("scope={:#?}", tcx.hir().get(scope));
match tcx.hir().get(scope) {
// We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
// This allows our visitor to process the defining item itself, causing
@ -684,10 +693,15 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
}
match locator.found {
Some((_, ty)) => ty,
Some(hidden) => hidden.ty,
None => {
let span = tcx.def_span(def_id);
tcx.sess.span_err(span, "could not find defining uses");
let name = tcx.item_name(tcx.parent(def_id.to_def_id()).unwrap());
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()
}
}

View File

@ -147,6 +147,12 @@ fn main() {
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");
if verbose > 2 {
let rust_env_vars =

View File

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

View File

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

View File

@ -1,8 +1,10 @@
error[E0277]: the trait bound `String: Copy` is not satisfied
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:32:18
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:33:9
|
LL | fn func() -> Self::Out {
| ^^^^^^^^^ the trait `Copy` is not implemented for `String`
LL | Box::new(AssocNoCopy)
| ^^^^^^^^^^^^^^^^^^^^^ 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

View File

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

View File

@ -2,18 +2,43 @@ error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
--> $DIR/impl-trait-return-missing-constraint.rs:25:13
|
LL | fn bar() -> impl Bar {
| -------- the found opaque type
| -------- the expected opaque type
...
LL | fn baz() -> impl Bar<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
| ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32`
|
= note: expected type `i32`
found associated type `<impl Bar as Foo>::Item`
= note: expected associated type `<impl Bar as Foo>::Item`
found type `i32`
= 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`
|
LL | fn bar() -> impl Bar<Item = i32> {
| ++++++++++++
error: aborting due to previous error
error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
--> $DIR/impl-trait-return-missing-constraint.rs:25:34
|
LL | fn bar() -> impl Bar {
| -------- the expected opaque type
...
LL | fn baz() -> impl Bar<Item = i32> {
| __________________________________^
LL | |
LL | |
LL | | bar()
LL | | }
| |_^ expected associated type, found `i32`
|
= note: expected associated type `<impl Bar as Foo>::Item`
found type `i32`
= 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`
|
LL | fn bar() -> impl Bar<Item = i32> {
| ++++++++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0271`.

View File

@ -8,10 +8,10 @@ LL | Box::new(async { x } )
| may outlive borrowed value `x`
|
note: async block is returned here
--> $DIR/async-borrowck-escaping-block-error.rs:4:20
--> $DIR/async-borrowck-escaping-block-error.rs:6:5
|
LL | fn test_boxed() -> Box<impl std::future::Future<Output = u32>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Box::new(async { x } )
| ^^^^^^^^^^^^^^^^^^^^^^
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 } )

View File

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

View File

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

View File

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

View File

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

View File

@ -7,5 +7,36 @@ LL | pub const async fn x() {}
| | `async` because of this
| `const` because of this
error: aborting due to previous error
error[E0391]: cycle detected when computing type of `x::{opaque#0}`
--> $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,7 +2,8 @@
// Test that impl trait does not allow creating recursive types that are
// otherwise forbidden when using `async` and `await`.
async fn recursive_async_function() -> () { //~ ERROR
async fn recursive_async_function() -> () {
//~^ ERROR recursion in an `async fn` requires boxing
recursive_async_function().await;
}

View File

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

View File

@ -29,10 +29,13 @@ LL | T: Generator<ResumeTy, Yield = ()>,
| ^^^^^^^^^^ required by this bound in `from_generator`
error[E0280]: the requirement `<impl Future as Future>::Output == u32` is not satisfied
--> $DIR/async.rs:7:25
--> $DIR/async.rs:7:29
|
LL | async fn foo(x: u32) -> u32 {
| ^^^
LL | async fn foo(x: u32) -> u32 {
| _____________________________^
LL | | x
LL | | }
| |_^
error: aborting due to 3 previous errors

View File

@ -8,10 +8,10 @@ LL | println!("{:?}", p);
| - `p` is borrowed here
|
note: closure is returned here
--> $DIR/borrowck-4.rs:8:14
--> $DIR/borrowck-4.rs:15:5
|
LL | fn foo () -> impl FnMut()->() {
| ^^^^^^^^^^^^^^^^
LL | c
| ^
help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
|
LL | let mut c = move || {

View File

@ -2,6 +2,7 @@
fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
//~^ ERROR `()` is not an iterator
//~| ERROR `()` is not an iterator
}
fn main() {}

View File

@ -6,6 +6,18 @@ LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
|
= help: the trait `Iterator` is not implemented for `()`
error: aborting due to previous error
error[E0277]: `()` is not an iterator
--> $DIR/conservative_impl_trait.rs:3:60
|
LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
| ____________________________________________________________^
LL | |
LL | |
LL | | }
| |_^ `()` is not an iterator
|
= help: the trait `Iterator` is not implemented for `()`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -5,6 +5,7 @@ impl<const N: u32> Trait for Uwu<N> {}
fn rawr() -> impl Trait {
//~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
//~| error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
Uwu::<10, 12>
}
@ -16,11 +17,13 @@ impl Traitor<1, 2> for u64 {}
fn uwu<const N: u8>() -> impl Traitor<N> {
//~^ error: the trait bound `u32: Traitor<N, N>` is not satisfied
//~| error: the trait bound `u32: Traitor<N, N>` is not satisfied
1_u32
}
fn owo() -> impl Traitor {
//~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
//~| error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
1_u64
}

View File

@ -7,8 +7,22 @@ LL | fn rawr() -> impl Trait {
= help: the following implementations were found:
<Uwu<N> as Trait>
error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
--> $DIR/rp_impl_trait_fail.rs:6:25
|
LL | fn rawr() -> impl Trait {
| _________________________^
LL | |
LL | |
LL | | Uwu::<10, 12>
LL | | }
| |_^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
|
= help: the following implementations were found:
<Uwu<N> as Trait>
error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
--> $DIR/rp_impl_trait_fail.rs:17:26
--> $DIR/rp_impl_trait_fail.rs:18:26
|
LL | fn uwu<const N: u8>() -> impl Traitor<N> {
| ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
@ -17,8 +31,23 @@ LL | fn uwu<const N: u8>() -> impl Traitor<N> {
<u32 as Traitor<N, 2_u8>>
<u64 as Traitor<1_u8, 2_u8>>
error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
--> $DIR/rp_impl_trait_fail.rs:18:42
|
LL | fn uwu<const N: u8>() -> impl Traitor<N> {
| __________________________________________^
LL | |
LL | |
LL | | 1_u32
LL | | }
| |_^ the trait `Traitor<N, N>` is not implemented for `u32`
|
= help: the following implementations were found:
<u32 as Traitor<N, 2_u8>>
<u64 as Traitor<1_u8, 2_u8>>
error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
--> $DIR/rp_impl_trait_fail.rs:22:13
--> $DIR/rp_impl_trait_fail.rs:24:13
|
LL | fn owo() -> impl Traitor {
| ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
@ -27,6 +56,21 @@ LL | fn owo() -> impl Traitor {
<u64 as Traitor<1_u8, 2_u8>>
<u32 as Traitor<N, 2_u8>>
error: aborting due to 3 previous errors
error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
--> $DIR/rp_impl_trait_fail.rs:24:26
|
LL | fn owo() -> impl Traitor {
| __________________________^
LL | |
LL | |
LL | | 1_u64
LL | | }
| |_^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
|
= help: the following implementations were found:
<u64 as Traitor<1_u8, 2_u8>>
<u32 as Traitor<N, 2_u8>>
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -3,11 +3,9 @@
#![allow(incomplete_features)]
pub mod foo {
type MainFn = impl Fn();
//~^ ERROR could not find defining uses
fn bar() {}
pub const BAR: MainFn = bar;
//~^ ERROR mismatched types [E0308]
}
use foo::BAR as main; //~ ERROR `main` function not found in crate

View File

@ -1,30 +1,11 @@
error[E0601]: `main` function not found in crate `imported_main_const_fn_item_type_forbidden`
--> $DIR/imported_main_const_fn_item_type_forbidden.rs:13:22
--> $DIR/imported_main_const_fn_item_type_forbidden.rs:11:22
|
LL | use foo::BAR as main;
| ---------------- ^ consider adding a `main` function to `$DIR/imported_main_const_fn_item_type_forbidden.rs`
| |
| non-function item at `crate::main` is found
error[E0308]: mismatched types
--> $DIR/imported_main_const_fn_item_type_forbidden.rs:9:29
|
LL | type MainFn = impl Fn();
| --------- the expected opaque type
...
LL | pub const BAR: MainFn = bar;
| ^^^ expected opaque type, found fn item
|
= note: expected opaque type `impl Fn()`
found fn item `fn() {bar}`
error: aborting due to previous error
error: could not find defining uses
--> $DIR/imported_main_const_fn_item_type_forbidden.rs:5:19
|
LL | type MainFn = impl Fn();
| ^^^^^^^^^
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0601.
For more information about an error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0601`.

View File

@ -1,13 +1,13 @@
// ignore-compare-mode-chalk
// check-pass
#![feature(type_alias_impl_trait)]
use std::fmt::Debug;
type Foo = impl Debug;
//~^ ERROR could not find defining uses
struct Bar(Foo);
fn define() -> Bar {
Bar(42) //~ ERROR mismatched types
Bar(42)
}
type Foo2 = impl Debug;
@ -17,21 +17,18 @@ fn define2() {
}
type Foo3 = impl Debug;
//~^ ERROR could not find defining uses
fn define3(x: Foo3) {
let y: i32 = x; //~ ERROR mismatched types
let y: i32 = x;
}
fn define3_1() {
define3(42) //~ ERROR mismatched types
define3(42)
}
type Foo4 = impl Debug;
//~^ ERROR could not find defining uses
fn define4() {
let y: Foo4 = 42;
//~^ ERROR mismatched types [E0308]
}
fn main() {}

View File

@ -1,73 +0,0 @@
error[E0308]: mismatched types
--> $DIR/feature-gate-type_alias_impl_trait.rs:10:9
|
LL | type Foo = impl Debug;
| ---------- the expected opaque type
...
LL | Bar(42)
| ^^ expected opaque type, found integer
|
= note: expected opaque type `impl Debug`
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/feature-gate-type_alias_impl_trait.rs:23:18
|
LL | type Foo3 = impl Debug;
| ---------- the found opaque type
...
LL | let y: i32 = x;
| --- ^ expected `i32`, found opaque type
| |
| expected due to this
|
= note: expected type `i32`
found opaque type `impl Debug`
error[E0308]: mismatched types
--> $DIR/feature-gate-type_alias_impl_trait.rs:26:13
|
LL | type Foo3 = impl Debug;
| ---------- the expected opaque type
...
LL | define3(42)
| ^^ expected opaque type, found integer
|
= note: expected opaque type `impl Debug`
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/feature-gate-type_alias_impl_trait.rs:33:19
|
LL | type Foo4 = impl Debug;
| ---------- the expected opaque type
...
LL | let y: Foo4 = 42;
| ---- ^^ expected opaque type, found integer
| |
| expected due to this
|
= note: expected opaque type `impl Debug`
found type `{integer}`
error: could not find defining uses
--> $DIR/feature-gate-type_alias_impl_trait.rs:5:12
|
LL | type Foo = impl Debug;
| ^^^^^^^^^^
error: could not find defining uses
--> $DIR/feature-gate-type_alias_impl_trait.rs:19:13
|
LL | type Foo3 = impl Debug;
| ^^^^^^^^^^
error: could not find defining uses
--> $DIR/feature-gate-type_alias_impl_trait.rs:29:13
|
LL | type Foo4 = impl Debug;
| ^^^^^^^^^^
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -6,10 +6,14 @@
use std::ops::Generator;
fn foo(bar: bool) -> impl Generator<(bool,)> {
//~^ ERROR: type mismatch in generator arguments [E0631]
//~| NOTE: expected signature of `fn((bool,)) -> _`
//~^ ERROR: type mismatch in generator arguments [E0631]
//~| ERROR: type mismatch in generator arguments [E0631]
//~| NOTE: expected signature of `fn((bool,)) -> _`
//~| NOTE: expected signature of `fn((bool,)) -> _`
//~| NOTE: in this expansion of desugaring of `impl Trait`
|bar| {
//~^ NOTE: found signature of `fn(bool) -> _`
//~^ NOTE: found signature of `fn(bool) -> _`
//~| NOTE: found signature of `fn(bool) -> _`
if bar {
yield bar;
}

View File

@ -7,6 +7,22 @@ LL | fn foo(bar: bool) -> impl Generator<(bool,)> {
LL | |bar| {
| ----- found signature of `fn(bool) -> _`
error: aborting due to previous error
error[E0631]: type mismatch in generator arguments
--> $DIR/issue-88653.rs:8:46
|
LL | fn foo(bar: bool) -> impl Generator<(bool,)> {
| ______________________________________________^
LL | |
LL | |
LL | |
... |
LL | | |bar| {
| | ----- found signature of `fn(bool) -> _`
... |
LL | | }
LL | | }
| |_^ expected signature of `fn((bool,)) -> _`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0631`.

View File

@ -2,7 +2,9 @@
use std::ops::Generator;
fn foo() -> impl Generator<Return = i32> { //~ ERROR type mismatch
fn foo() -> impl Generator<Return = i32> {
//~^ ERROR type mismatch
//~| ERROR type mismatch
|| {
if false {
return Ok(6);

View File

@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/type-mismatch-signature-deduction.rs:13:9
--> $DIR/type-mismatch-signature-deduction.rs:15:9
|
LL | 5
| ^ expected enum `Result`, found integer
@ -7,21 +7,37 @@ LL | 5
= note: expected type `Result<{integer}, _>`
found type `{integer}`
note: return type inferred to be `Result<{integer}, _>` here
--> $DIR/type-mismatch-signature-deduction.rs:8:20
--> $DIR/type-mismatch-signature-deduction.rs:10:20
|
LL | return Ok(6);
| ^^^^^
error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6] as Generator>::Return == i32`
error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:8:5: 16:6] as Generator>::Return == i32`
--> $DIR/type-mismatch-signature-deduction.rs:5:13
|
LL | fn foo() -> impl Generator<Return = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found enum `Result`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `i32`
|
= note: expected type `i32`
found enum `Result<{integer}, _>`
= note: expected enum `Result<{integer}, _>`
found type `i32`
error: aborting due to 2 previous errors
error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:8:5: 16:6] as Generator>::Return == i32`
--> $DIR/type-mismatch-signature-deduction.rs:5:42
|
LL | fn foo() -> impl Generator<Return = i32> {
| __________________________________________^
LL | |
LL | |
LL | | || {
... |
LL | | }
LL | | }
| |_^ expected enum `Result`, found `i32`
|
= note: expected enum `Result<{integer}, _>`
found type `i32`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0271, E0308.
For more information about an error, try `rustc --explain E0271`.

View File

@ -1,4 +1,4 @@
error[E0477]: the type `impl Stream<Item = i32>` does not fulfill the required lifetime
error[E0477]: the type `<() as Yay<&'a ()>>::InnerStream<'s>` does not fulfill the required lifetime
--> $DIR/issue-86218.rs:23:28
|
LL | type InnerStream<'s> = impl Stream<Item = i32> + 's;
@ -10,6 +10,14 @@ note: type must outlive the lifetime `'s` as defined here as required by this bi
LL | type InnerStream<'s> = impl Stream<Item = i32> + 's;
| ^^
error: aborting due to previous error
error: unconstrained opaque type
--> $DIR/issue-86218.rs:23:28
|
LL | type InnerStream<'s> = impl Stream<Item = i32> + 's;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `InnerStream` must be used in combination with a concrete type within the same module
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0477`.

View File

@ -1,21 +1,19 @@
error[E0271]: type mismatch resolving `<impl Future as Future>::Output == impl Stream<Item = Repr>`
--> $DIR/issue-89008.rs:39:43
error[E0271]: type mismatch resolving `<Empty<_> as Stream>::Item == Repr`
--> $DIR/issue-89008.rs:40:9
|
LL | type LineStream<'a, Repr> = impl Stream<Item = Repr>;
| ------------------------ the expected opaque type
...
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found struct `Empty`
| ---- this type parameter
LL | async {empty()}
| ^^^^^^^^^^^^^^^ type mismatch resolving `<Empty<_> as Stream>::Item == Repr`
|
= note: expected opaque type `impl Stream<Item = Repr>`
found struct `Empty<_>`
error: could not find defining uses
--> $DIR/issue-89008.rs:35:33
note: expected this to be `()`
--> $DIR/issue-89008.rs:18:17
|
LL | type LineStream<'a, Repr> = impl Stream<Item = Repr>;
| ^^^^^^^^^^^^^^^^^^^^^^^^
LL | type Item = ();
| ^^
= note: expected unit type `()`
found type parameter `Repr`
error: aborting due to 2 previous errors
error: aborting due to previous error
For more information about this error, try `rustc --explain E0271`.

View File

@ -16,7 +16,8 @@ pub trait Trait2 {
impl<'c, S: Trait2> Trait2 for &'c mut S {
type FooFuture<'a> = impl Trait1;
fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
//~^ ERROR unconstrained opaque type
fn foo<'a>() -> Self::FooFuture<'a> {
Struct(unimplemented!())
}
}

View File

@ -1,11 +1,10 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/issue-87258_a.rs:19:21
error: unconstrained opaque type
--> $DIR/issue-87258_a.rs:18:26
|
LL | fn foo<'a>() -> Self::FooFuture<'a> {
| ^^^^^^^^^^^^^^^^^^^
LL | type FooFuture<'a> = impl Trait1;
| ^^^^^^^^^^^
|
= note: hidden type `Struct<'_>` captures lifetime '_#7r
= note: `FooFuture` must be used in combination with a concrete type within the same module
error: aborting due to previous error
For more information about this error, try `rustc --explain E0700`.

View File

@ -15,10 +15,11 @@ pub trait Trait2 {
}
type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
//~^ ERROR unconstrained opaque type
impl<'c, S: Trait2> Trait2 for &'c mut S {
type FooFuture<'a> = Helper<'c, 'a, S>;
fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
fn foo<'a>() -> Self::FooFuture<'a> {
Struct(unimplemented!())
}
}

View File

@ -1,11 +1,10 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/issue-87258_b.rs:21:21
error: unconstrained opaque type
--> $DIR/issue-87258_b.rs:17:49
|
LL | fn foo<'a>() -> Self::FooFuture<'a> {
| ^^^^^^^^^^^^^^^^^^^
LL | type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
| ^^^^^^^^^^^
|
= note: hidden type `Struct<'_>` captures lifetime '_#7r
= note: `Helper` must be used in combination with a concrete type within the same module
error: aborting due to previous error
For more information about this error, try `rustc --explain E0700`.

View File

@ -17,7 +17,6 @@ struct C;
impl<'a> A<'a> for C {
type B<'b> = impl Clone;
//~^ ERROR: could not find defining uses
fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
}

View File

@ -1,8 +1,8 @@
error: non-defining opaque type use in defining scope
--> $DIR/issue-88595.rs:22:23
--> $DIR/issue-88595.rs:21:35
|
LL | fn a(&'a self) -> Self::B<'a> {}
| ^^^^^^^^^^^
| ^^
|
note: lifetime used multiple times
--> $DIR/issue-88595.rs:18:6
@ -12,11 +12,5 @@ LL | impl<'a> A<'a> for C {
LL | type B<'b> = impl Clone;
| ^^
error: could not find defining uses
--> $DIR/issue-88595.rs:19:18
|
LL | type B<'b> = impl Clone;
| ^^^^^^^^^^
error: aborting due to 2 previous errors
error: aborting due to previous error

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