Skip to content

Commit

Permalink
typeck: record impl Trait concrete resolutions.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Aug 12, 2016
1 parent 1ef7ddf commit d92e594
Show file tree
Hide file tree
Showing 10 changed files with 1,224 additions and 96 deletions.
8 changes: 8 additions & 0 deletions src/librustc/hir/map/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
});
}

fn visit_ty(&mut self, ty: &'ast Ty) {
self.insert(ty.id, NodeTy(ty));

self.with_parent(ty.id, |this| {
intravisit::walk_ty(this, ty);
});
}

fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
b: &'ast Block, s: Span, id: NodeId) {
assert_eq!(self.parent_node, id);
Expand Down
12 changes: 12 additions & 0 deletions src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub enum Node<'ast> {
NodeVariant(&'ast Variant),
NodeExpr(&'ast Expr),
NodeStmt(&'ast Stmt),
NodeTy(&'ast Ty),
NodeLocal(&'ast Pat),
NodePat(&'ast Pat),
NodeBlock(&'ast Block),
Expand All @@ -76,6 +77,7 @@ pub enum MapEntry<'ast> {
EntryVariant(NodeId, &'ast Variant),
EntryExpr(NodeId, &'ast Expr),
EntryStmt(NodeId, &'ast Stmt),
EntryTy(NodeId, &'ast Ty),
EntryLocal(NodeId, &'ast Pat),
EntryPat(NodeId, &'ast Pat),
EntryBlock(NodeId, &'ast Block),
Expand Down Expand Up @@ -104,6 +106,7 @@ impl<'ast> MapEntry<'ast> {
NodeVariant(n) => EntryVariant(p, n),
NodeExpr(n) => EntryExpr(p, n),
NodeStmt(n) => EntryStmt(p, n),
NodeTy(n) => EntryTy(p, n),
NodeLocal(n) => EntryLocal(p, n),
NodePat(n) => EntryPat(p, n),
NodeBlock(n) => EntryBlock(p, n),
Expand All @@ -122,6 +125,7 @@ impl<'ast> MapEntry<'ast> {
EntryVariant(id, _) => id,
EntryExpr(id, _) => id,
EntryStmt(id, _) => id,
EntryTy(id, _) => id,
EntryLocal(id, _) => id,
EntryPat(id, _) => id,
EntryBlock(id, _) => id,
Expand All @@ -144,6 +148,7 @@ impl<'ast> MapEntry<'ast> {
EntryVariant(_, n) => NodeVariant(n),
EntryExpr(_, n) => NodeExpr(n),
EntryStmt(_, n) => NodeStmt(n),
EntryTy(_, n) => NodeTy(n),
EntryLocal(_, n) => NodeLocal(n),
EntryPat(_, n) => NodePat(n),
EntryBlock(_, n) => NodeBlock(n),
Expand Down Expand Up @@ -257,6 +262,7 @@ impl<'ast> Map<'ast> {
EntryVariant(p, _) |
EntryExpr(p, _) |
EntryStmt(p, _) |
EntryTy(p, _) |
EntryLocal(p, _) |
EntryPat(p, _) |
EntryBlock(p, _) |
Expand Down Expand Up @@ -297,6 +303,7 @@ impl<'ast> Map<'ast> {
EntryVariant(p, _) |
EntryExpr(p, _) |
EntryStmt(p, _) |
EntryTy(p, _) |
EntryLocal(p, _) |
EntryPat(p, _) |
EntryBlock(p, _) |
Expand Down Expand Up @@ -680,6 +687,7 @@ impl<'ast> Map<'ast> {
Some(NodeVariant(variant)) => variant.span,
Some(NodeExpr(expr)) => expr.span,
Some(NodeStmt(stmt)) => stmt.span,
Some(NodeTy(ty)) => ty.span,
Some(NodeLocal(pat)) => pat.span,
Some(NodePat(pat)) => pat.span,
Some(NodeBlock(block)) => block.span,
Expand Down Expand Up @@ -971,6 +979,7 @@ impl<'a> NodePrinter for pprust::State<'a> {
NodeVariant(a) => self.print_variant(&a),
NodeExpr(a) => self.print_expr(&a),
NodeStmt(a) => self.print_stmt(&a),
NodeTy(a) => self.print_type(&a),
NodePat(a) => self.print_pat(&a),
NodeBlock(a) => self.print_block(&a),
NodeLifetime(a) => self.print_lifetime(&a),
Expand Down Expand Up @@ -1059,6 +1068,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
Some(NodeStmt(ref stmt)) => {
format!("stmt {}{}", pprust::stmt_to_string(&stmt), id_str)
}
Some(NodeTy(ref ty)) => {
format!("type {}{}", pprust::ty_to_string(&ty), id_str)
}
Some(NodeLocal(ref pat)) => {
format!("local {}{}", pprust::pat_to_string(&pat), id_str)
}
Expand Down
14 changes: 14 additions & 0 deletions src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1390,6 +1390,20 @@ impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
intravisit::walk_foreign_item(self, ni);
encode_info_for_foreign_item(self.ecx, self.rbml_w_for_visit_item, ni, self.index);
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
intravisit::walk_ty(self, ty);

if let hir::TyImplTrait(_) = ty.node {
let rbml_w = &mut *self.rbml_w_for_visit_item;
let def_id = self.ecx.tcx.map.local_def_id(ty.id);
let _task = self.index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(self.ecx, rbml_w, def_id);
encode_family(rbml_w, 'y');
encode_bounds_and_type_for_item(rbml_w, self.ecx, self.index, ty.id);
rbml_w.end_tag();
}
}
}

fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
Expand Down
33 changes: 18 additions & 15 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1763,25 +1763,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {

// Create the anonymized type.
let def_id = tcx.map.local_def_id(ast_ty.id);
let substs = if let Some(anon_scope) = rscope.anon_type_scope() {
anon_scope.fresh_substs(tcx)
if let Some(anon_scope) = rscope.anon_type_scope() {
let substs = anon_scope.fresh_substs(tcx);
let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs);

// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
let bounds = compute_bounds(self, ty, bounds,
SizedByDefault::Yes,
Some(anon_scope),
ast_ty.span);
let predicates = bounds.predicates(tcx, ty);
let predicates = tcx.lift_to_global(&predicates).unwrap();
tcx.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
predicates: VecPerParamSpace::new(vec![], vec![], predicates)
});

ty
} else {
span_err!(tcx.sess, ast_ty.span, E0562,
"`impl Trait` not allowed outside of function \
and inherent method return types");
tcx.mk_substs(Substs::empty())
};
let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs);

// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
let bounds = compute_bounds(self, ty, bounds, SizedByDefault::Yes, ast_ty.span);
let predicates = tcx.lift_to_global(&bounds.predicates(tcx, ty)).unwrap();
let predicates = ty::GenericPredicates {
predicates: VecPerParamSpace::new(vec![], vec![], predicates)
};
tcx.predicates.borrow_mut().insert(def_id, predicates);

ty
tcx.types.err
}
}
hir::TyPath(ref maybe_qself, ref path) => {
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
Expand Down
82 changes: 60 additions & 22 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
use rustc::ty::{MethodCall, MethodCallee};
use rustc::ty::adjustment;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
use rustc::ty::util::{Representability, IntTypeExt};
use require_c_abi_if_variadic;
use rscope::{ElisionFailureInfo, RegionScope};
Expand Down Expand Up @@ -172,6 +172,12 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'gcx, 'tcx>>>>,

deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,

// Anonymized 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
// deanonymize TyAnon, after typeck is done with all functions.
anon_types: RefCell<DefIdMap<Ty<'tcx>>>,
}

impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
Expand Down Expand Up @@ -408,6 +414,7 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> {
locals: RefCell::new(NodeMap()),
deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()),
anon_types: RefCell::new(DefIdMap()),
})
})
}
Expand Down Expand Up @@ -631,32 +638,29 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
body: &'gcx hir::Block)
-> FnCtxt<'a, 'gcx, 'tcx>
{
let arg_tys = &fn_sig.inputs;
let ret_ty = fn_sig.output;
let mut fn_sig = fn_sig.clone();

debug!("check_fn(arg_tys={:?}, ret_ty={:?}, fn_id={})",
arg_tys,
ret_ty,
fn_id);
debug!("check_fn(sig={:?}, fn_id={})", fn_sig, fn_id);

// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
let fcx = FnCtxt::new(inherited, ret_ty, body.id);
let mut fcx = FnCtxt::new(inherited, fn_sig.output, body.id);
*fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);

if let ty::FnConverging(ret_ty) = ret_ty {
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
}

debug!("fn-sig-map: fn_id={} fn_sig={:?}", fn_id, fn_sig);

inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig.clone());
fn_sig.output = match fcx.ret_ty {
ty::FnConverging(orig_ret_ty) => {
fcx.require_type_is_sized(orig_ret_ty, decl.output.span(), traits::ReturnType);
ty::FnConverging(fcx.instantiate_anon_types(&orig_ret_ty))
}
ty::FnDiverging => ty::FnDiverging
};
fcx.ret_ty = fn_sig.output;

{
let mut visit = GatherLocalsVisitor { fcx: &fcx, };

// Add formal parameters.
for (arg_ty, input) in arg_tys.iter().zip(&decl.inputs) {
for (arg_ty, input) in fn_sig.inputs.iter().zip(&decl.inputs) {
// The type of the argument must be well-formed.
//
// NB -- this is now checked in wfcheck, but that
Expand All @@ -672,21 +676,20 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
});

// Check the pattern.
fcx.check_pat(&input.pat, *arg_ty);
fcx.check_pat(&input.pat, arg_ty);
fcx.write_ty(input.id, arg_ty);
}

visit.visit_block(body);
}

fcx.check_block_with_expected(body, match ret_ty {
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);

fcx.check_block_with_expected(body, match fcx.ret_ty {
ty::FnConverging(result_type) => ExpectHasType(result_type),
ty::FnDiverging => NoExpectation
});

for (input, arg) in decl.inputs.iter().zip(arg_tys) {
fcx.write_ty(input.id, arg);
}

fcx
}

Expand Down Expand Up @@ -1623,6 +1626,41 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}

/// Replace all anonymized types with fresh inference variables
/// and record them for writeback.
fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
value.fold_with(&mut BottomUpFolder { tcx: self.tcx, fldop: |ty| {
if let ty::TyAnon(def_id, substs) = ty.sty {
// Use the same type variable if the exact same TyAnon appears more
// than once in the return type (e.g. if it's pased to a type alias).
if let Some(ty_var) = self.anon_types.borrow().get(&def_id) {
return ty_var;
}
let ty_var = self.next_ty_var();
self.anon_types.borrow_mut().insert(def_id, ty_var);

let item_predicates = self.tcx.lookup_predicates(def_id);
let bounds = item_predicates.instantiate(self.tcx, substs);

let span = self.tcx.map.def_id_span(def_id, codemap::DUMMY_SP);
for predicate in bounds.predicates {
// Change the predicate to refer to the type variable,
// which will be the concrete type, instead of the TyAnon.
// This also instantiates nested `impl Trait`.
let predicate = self.instantiate_anon_types(&predicate);

// Require that the predicate holds for the concrete type.
let cause = traits::ObligationCause::new(span, self.body_id,
traits::ReturnType);
self.register_predicate(traits::Obligation::new(cause, predicate));
}

ty_var
} else {
ty
}
}})
}

fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
where T : TypeFoldable<'tcx>
Expand Down
Loading

0 comments on commit d92e594

Please sign in to comment.