Skip to content

Commit bc552fc

Browse files
committed
Move instantiate_opaque_types to rustc_infer.
It does not depend on anything from rustc_trait_selection anymore.
1 parent a8f06b2 commit bc552fc

File tree

6 files changed

+283
-294
lines changed

6 files changed

+283
-294
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ use rustc_span::def_id::CRATE_DEF_ID;
3636
use rustc_span::{Span, DUMMY_SP};
3737
use rustc_target::abi::VariantIdx;
3838
use rustc_trait_selection::infer::InferCtxtExt as _;
39-
use rustc_trait_selection::opaque_types::InferCtxtExt;
4039
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
4140
use rustc_trait_selection::traits::query::type_op;
4241
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;

compiler/rustc_infer/src/infer/opaque_types.rs

+278-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
use crate::infer::InferCtxt;
1+
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
2+
use crate::infer::{InferCtxt, InferOk};
3+
use crate::traits;
24
use rustc_data_structures::sync::Lrc;
35
use rustc_data_structures::vec_map::VecMap;
46
use rustc_hir as hir;
5-
use rustc_middle::ty::subst::GenericArgKind;
7+
use rustc_hir::def_id::LocalDefId;
8+
use rustc_middle::ty::fold::BottomUpFolder;
9+
use rustc_middle::ty::subst::{GenericArgKind, Subst};
610
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
711
use rustc_span::Span;
812

@@ -52,6 +56,49 @@ pub struct OpaqueTypeDecl<'tcx> {
5256
}
5357

5458
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
59+
/// Replaces all opaque types in `value` with fresh inference variables
60+
/// and creates appropriate obligations. For example, given the input:
61+
///
62+
/// impl Iterator<Item = impl Debug>
63+
///
64+
/// this method would create two type variables, `?0` and `?1`. It would
65+
/// return the type `?0` but also the obligations:
66+
///
67+
/// ?0: Iterator<Item = ?1>
68+
/// ?1: Debug
69+
///
70+
/// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
71+
/// info about the `impl Iterator<..>` type and `?1` to info about
72+
/// the `impl Debug` type.
73+
///
74+
/// # Parameters
75+
///
76+
/// - `parent_def_id` -- the `DefId` of the function in which the opaque type
77+
/// is defined
78+
/// - `body_id` -- the body-id with which the resulting obligations should
79+
/// be associated
80+
/// - `param_env` -- the in-scope parameter environment to be used for
81+
/// obligations
82+
/// - `value` -- the value within which we are instantiating opaque types
83+
/// - `value_span` -- the span where the value came from, used in error reporting
84+
pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
85+
&self,
86+
body_id: hir::HirId,
87+
param_env: ty::ParamEnv<'tcx>,
88+
value: T,
89+
value_span: Span,
90+
) -> InferOk<'tcx, T> {
91+
debug!(
92+
"instantiate_opaque_types(value={:?}, body_id={:?}, \
93+
param_env={:?}, value_span={:?})",
94+
value, body_id, param_env, value_span,
95+
);
96+
let mut instantiator =
97+
Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
98+
let value = instantiator.instantiate_opaque_types_in_map(value);
99+
InferOk { value, obligations: instantiator.obligations }
100+
}
101+
55102
/// Given the map `opaque_types` containing the opaque
56103
/// `impl Trait` types whose underlying, hidden types are being
57104
/// inferred, this method adds constraints to the regions
@@ -359,3 +406,232 @@ where
359406
ControlFlow::CONTINUE
360407
}
361408
}
409+
410+
struct Instantiator<'a, 'tcx> {
411+
infcx: &'a InferCtxt<'a, 'tcx>,
412+
body_id: hir::HirId,
413+
param_env: ty::ParamEnv<'tcx>,
414+
value_span: Span,
415+
obligations: Vec<traits::PredicateObligation<'tcx>>,
416+
}
417+
418+
impl<'a, 'tcx> Instantiator<'a, 'tcx> {
419+
fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
420+
let tcx = self.infcx.tcx;
421+
value.fold_with(&mut BottomUpFolder {
422+
tcx,
423+
ty_op: |ty| {
424+
if ty.references_error() {
425+
return tcx.ty_error();
426+
} else if let ty::Opaque(def_id, substs) = ty.kind() {
427+
// Check that this is `impl Trait` type is
428+
// declared by `parent_def_id` -- i.e., one whose
429+
// value we are inferring. At present, this is
430+
// always true during the first phase of
431+
// type-check, but not always true later on during
432+
// NLL. Once we support named opaque types more fully,
433+
// this same scenario will be able to arise during all phases.
434+
//
435+
// Here is an example using type alias `impl Trait`
436+
// that indicates the distinction we are checking for:
437+
//
438+
// ```rust
439+
// mod a {
440+
// pub type Foo = impl Iterator;
441+
// pub fn make_foo() -> Foo { .. }
442+
// }
443+
//
444+
// mod b {
445+
// fn foo() -> a::Foo { a::make_foo() }
446+
// }
447+
// ```
448+
//
449+
// Here, the return type of `foo` references an
450+
// `Opaque` indeed, but not one whose value is
451+
// presently being inferred. You can get into a
452+
// similar situation with closure return types
453+
// today:
454+
//
455+
// ```rust
456+
// fn foo() -> impl Iterator { .. }
457+
// fn bar() {
458+
// let x = || foo(); // returns the Opaque assoc with `foo`
459+
// }
460+
// ```
461+
if let Some(def_id) = def_id.as_local() {
462+
let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
463+
let parent_def_id = self.infcx.defining_use_anchor;
464+
let def_scope_default = || {
465+
let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
466+
parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
467+
};
468+
let (in_definition_scope, origin) =
469+
match tcx.hir().expect_item(opaque_hir_id).kind {
470+
// Anonymous `impl Trait`
471+
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
472+
impl_trait_fn: Some(parent),
473+
origin,
474+
..
475+
}) => (parent == parent_def_id.to_def_id(), origin),
476+
// Named `type Foo = impl Bar;`
477+
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
478+
impl_trait_fn: None,
479+
origin,
480+
..
481+
}) => (
482+
may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
483+
origin,
484+
),
485+
_ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
486+
};
487+
if in_definition_scope {
488+
let opaque_type_key =
489+
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
490+
return self.fold_opaque_ty(ty, opaque_type_key, origin);
491+
}
492+
493+
debug!(
494+
"instantiate_opaque_types_in_map: \
495+
encountered opaque outside its definition scope \
496+
def_id={:?}",
497+
def_id,
498+
);
499+
}
500+
}
501+
502+
ty
503+
},
504+
lt_op: |lt| lt,
505+
ct_op: |ct| ct,
506+
})
507+
}
508+
509+
#[instrument(skip(self), level = "debug")]
510+
fn fold_opaque_ty(
511+
&mut self,
512+
ty: Ty<'tcx>,
513+
opaque_type_key: OpaqueTypeKey<'tcx>,
514+
origin: hir::OpaqueTyOrigin,
515+
) -> Ty<'tcx> {
516+
let infcx = self.infcx;
517+
let tcx = infcx.tcx;
518+
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
519+
520+
// Use the same type variable if the exact same opaque type appears more
521+
// than once in the return type (e.g., if it's passed to a type alias).
522+
if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
523+
debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
524+
return opaque_defn.concrete_ty;
525+
}
526+
527+
let ty_var = infcx.next_ty_var(TypeVariableOrigin {
528+
kind: TypeVariableOriginKind::TypeInference,
529+
span: self.value_span,
530+
});
531+
532+
// Ideally, we'd get the span where *this specific `ty` came
533+
// from*, but right now we just use the span from the overall
534+
// value being folded. In simple cases like `-> impl Foo`,
535+
// these are the same span, but not in cases like `-> (impl
536+
// Foo, impl Bar)`.
537+
let definition_span = self.value_span;
538+
539+
{
540+
let mut infcx = self.infcx.inner.borrow_mut();
541+
infcx.opaque_types.insert(
542+
OpaqueTypeKey { def_id, substs },
543+
OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
544+
);
545+
infcx.opaque_types_vars.insert(ty_var, ty);
546+
}
547+
548+
debug!("generated new type inference var {:?}", ty_var.kind());
549+
550+
let item_bounds = tcx.explicit_item_bounds(def_id);
551+
552+
self.obligations.reserve(item_bounds.len());
553+
for (predicate, _) in item_bounds {
554+
debug!(?predicate);
555+
let predicate = predicate.subst(tcx, substs);
556+
debug!(?predicate);
557+
558+
// We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
559+
let predicate = predicate.fold_with(&mut BottomUpFolder {
560+
tcx,
561+
ty_op: |ty| match ty.kind() {
562+
ty::Projection(projection_ty) => infcx.infer_projection(
563+
self.param_env,
564+
*projection_ty,
565+
traits::ObligationCause::misc(self.value_span, self.body_id),
566+
0,
567+
&mut self.obligations,
568+
),
569+
_ => ty,
570+
},
571+
lt_op: |lt| lt,
572+
ct_op: |ct| ct,
573+
});
574+
debug!(?predicate);
575+
576+
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
577+
if projection.ty.references_error() {
578+
// No point on adding these obligations since there's a type error involved.
579+
return tcx.ty_error();
580+
}
581+
}
582+
// Change the predicate to refer to the type variable,
583+
// which will be the concrete type instead of the opaque type.
584+
// This also instantiates nested instances of `impl Trait`.
585+
let predicate = self.instantiate_opaque_types_in_map(predicate);
586+
587+
let cause =
588+
traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
589+
590+
// Require that the predicate holds for the concrete type.
591+
debug!(?predicate);
592+
self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
593+
}
594+
595+
ty_var
596+
}
597+
}
598+
599+
/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
600+
///
601+
/// Example:
602+
/// ```rust
603+
/// pub mod foo {
604+
/// pub mod bar {
605+
/// pub trait Bar { .. }
606+
///
607+
/// pub type Baz = impl Bar;
608+
///
609+
/// fn f1() -> Baz { .. }
610+
/// }
611+
///
612+
/// fn f2() -> bar::Baz { .. }
613+
/// }
614+
/// ```
615+
///
616+
/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
617+
/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
618+
/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
619+
fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
620+
let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
621+
622+
// Named opaque types can be defined by any siblings or children of siblings.
623+
let scope = tcx.hir().get_defining_scope(opaque_hir_id);
624+
// We walk up the node tree until we hit the root or the scope of the opaque type.
625+
while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
626+
hir_id = tcx.hir().get_parent_item(hir_id);
627+
}
628+
// Syntactically, we are allowed to define the concrete type if:
629+
let res = hir_id == scope;
630+
trace!(
631+
"may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
632+
tcx.hir().find(hir_id),
633+
tcx.hir().get(opaque_hir_id),
634+
res
635+
);
636+
res
637+
}

0 commit comments

Comments
 (0)