diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 4e78d79ef8737..4f365a97f4ceb 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -524,10 +524,9 @@ for ty::TypeVariants<'tcx> region.hash_stable(hcx, hasher); pointee_ty.hash_stable(hcx, hasher); } - TyFnDef(def_id, substs, ref sig) => { + TyFnDef(def_id, substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); - sig.hash_stable(hcx, hasher); } TyFnPtr(ref sig) => { sig.hash_stable(hcx, hasher); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index f96e8c389d68d..d5020b12ee00e 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1369,7 +1369,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { Some(self.tcx.closure_kind(def_id)) } - pub fn closure_type(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> { + /// Obtain the signature of a function or closure. + /// For closures, unlike `tcx.fn_sig(def_id)`, this method will + /// work during the type-checking of the enclosing function and + /// return the closure signature in its partially inferred state. + pub fn fn_sig(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> { if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { if let Some(&ty) = tables.borrow().closure_tys.get(&id) { @@ -1378,7 +1382,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - self.tcx.closure_type(def_id) + self.tcx.fn_sig(def_id) } } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 74e1225f3948b..eab5a8f910331 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -12,7 +12,7 @@ //! `unsafe`. use self::RootUnsafeContext::*; -use ty::{self, Ty, TyCtxt}; +use ty::{self, TyCtxt}; use lint; use syntax::ast; @@ -40,14 +40,6 @@ enum RootUnsafeContext { UnsafeBlock(ast::NodeId), } -fn type_is_unsafe_function(ty: Ty) -> bool { - match ty.sty { - ty::TyFnDef(.., f) | - ty::TyFnPtr(f) => f.unsafety() == hir::Unsafety::Unsafe, - _ => false, - } -} - struct EffectCheckVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>, @@ -174,10 +166,11 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { match expr.node { hir::ExprMethodCall(..) => { let def_id = self.tables.type_dependent_defs[&expr.id].def_id(); - let base_type = self.tcx.type_of(def_id); - debug!("effect: method call case, base type is {:?}", - base_type); - if type_is_unsafe_function(base_type) { + let sig = self.tcx.fn_sig(def_id); + debug!("effect: method call case, signature is {:?}", + sig); + + if sig.0.unsafety == hir::Unsafety::Unsafe { self.require_unsafe(expr.span, "invocation of unsafe method") } @@ -186,8 +179,13 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { let base_type = self.tables.expr_ty_adjusted(base); debug!("effect: call case, base type is {:?}", base_type); - if type_is_unsafe_function(base_type) { - self.require_unsafe(expr.span, "call to unsafe function") + match base_type.sty { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { + if base_type.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe { + self.require_unsafe(expr.span, "call to unsafe function") + } + } + _ => {} } } hir::ExprUnary(hir::UnDeref, ref base) => { diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index f180ae53b8ae1..fde207e4b2f79 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -66,11 +66,8 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'tcx> ExprVisitor<'a, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { - let intrinsic = match self.tcx.type_of(def_id).sty { - ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic, - _ => return false - }; - intrinsic && self.tcx.item_name(def_id) == "transmute" + self.tcx.fn_sig(def_id).abi() == RustIntrinsic && + self.tcx.item_name(def_id) == "transmute" } fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) { @@ -153,22 +150,14 @@ impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { } else { Def::Err }; - match def { - Def::Fn(did) if self.def_id_is_transmute(did) => { + if let Def::Fn(did) = def { + if self.def_id_is_transmute(did) { let typ = self.tables.node_id_to_type(expr.id); - let typ = self.tcx.lift_to_global(&typ).unwrap(); - match typ.sty { - ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => { - let from = sig.inputs().skip_binder()[0]; - let to = *sig.output().skip_binder(); - self.check_transmute(expr.span, from, to); - } - _ => { - span_bug!(expr.span, "transmute wasn't a bare fn?!"); - } - } + let sig = typ.fn_sig(self.tcx); + let from = sig.inputs().skip_binder()[0]; + let to = *sig.output().skip_binder(); + self.check_transmute(expr.span, from, to); } - _ => {} } intravisit::walk_expr(self, expr); diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 0e3a53129d157..c6c052fa4b1bc 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // The `Self` type is erased, so it should not appear in list of // arguments or return type apart from the receiver. - let ref sig = self.type_of(method.def_id).fn_sig(); + let ref sig = self.fn_sig(method.def_id); for input_ty in &sig.skip_binder().inputs()[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 787452121d375..c356e53234d9c 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1137,9 +1137,19 @@ fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>( -> Progress<'tcx> { let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); - let sig = fn_type.fn_sig(); + let sig = fn_type.fn_sig(selcx.tcx()); + let Normalized { + value: sig, + obligations + } = normalize_with_depth(selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth+1, + &sig); + confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) .with_addl_obligations(fn_pointer_vtable.nested) + .with_addl_obligations(obligations) } fn confirm_closure_candidate<'cx, 'gcx, 'tcx>( @@ -1149,7 +1159,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>( -> Progress<'tcx> { let closure_typer = selcx.closure_typer(); - let closure_type = closure_typer.closure_type(vtable.closure_def_id) + let closure_type = closure_typer.fn_sig(vtable.closure_def_id) .subst(selcx.tcx(), vtable.substs.substs); let Normalized { value: closure_type, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 10710d963a015..a66b6b863541e 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1404,19 +1404,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // provide an impl, but only for suitable `fn` pointers - ty::TyFnDef(.., ty::Binder(ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - variadic: false, - .. - })) | - ty::TyFnPtr(ty::Binder(ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - variadic: false, - .. - })) => { - candidates.vec.push(FnPointerCandidate); + ty::TyFnDef(..) | ty::TyFnPtr(_) => { + if let ty::Binder(ty::FnSig { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + variadic: false, + .. + }) = self_ty.fn_sig(self.tcx()) { + candidates.vec.push(FnPointerCandidate); + } } _ => { } @@ -2348,7 +2344,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // ok to skip binder; it is reintroduced below let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let sig = self_ty.fn_sig(); + let sig = self_ty.fn_sig(self.tcx()); let trait_ref = self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(), self_ty, @@ -2356,11 +2352,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { util::TupleArgumentsFlag::Yes) .map_bound(|(trait_ref, _)| trait_ref); + let Normalized { value: trait_ref, obligations } = + project::normalize_with_depth(self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_ref); + self.confirm_poly_trait_refs(obligation.cause.clone(), obligation.param_env, obligation.predicate.to_poly_trait_ref(), trait_ref)?; - Ok(VtableFnPointerData { fn_ty: self_ty, nested: vec![] }) + Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations }) } fn confirm_closure_candidate(&mut self, @@ -2799,7 +2802,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { substs: ty::ClosureSubsts<'tcx>) -> ty::PolyTraitRef<'tcx> { - let closure_type = self.infcx.closure_type(closure_def_id) + let closure_type = self.infcx.fn_sig(closure_def_id) .subst(self.tcx(), substs.substs); let ty::Binder((trait_ref, _)) = self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 2d81606329e57..5f869fc5567ee 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1378,9 +1378,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_fn_def(self, def_id: DefId, - substs: &'tcx Substs<'tcx>, - fty: PolyFnSig<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyFnDef(def_id, substs, fty)) + substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyFnDef(def_id, substs)) } pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 3d2cc4c598a22..68f85ba7d33e2 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -68,6 +68,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // view of possibly unifying simplify_type(tcx, mt.ty, can_simplify_params) } + ty::TyFnDef(def_id, _) | ty::TyClosure(def_id, _) => { Some(ClosureSimplifiedType(def_id)) } @@ -75,7 +76,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyTuple(ref tys, _) => { Some(TupleSimplifiedType(tys.len())) } - ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => { + ty::TyFnPtr(ref f) => { Some(FunctionSimplifiedType(f.skip_binder().inputs().len())) } ty::TyProjection(_) | ty::TyParam(_) => { diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 46afa6ee7d011..d5aa9f55ff0c4 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -155,9 +155,8 @@ impl FlagComputation { self.add_tys(&ts[..]); } - &ty::TyFnDef(_, substs, f) => { + &ty::TyFnDef(_, substs) => { self.add_substs(substs); - self.add_fn_sig(f); } &ty::TyFnPtr(f) => { diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 09a3bcd061380..b9896e0cecf5d 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -348,7 +348,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option { .filter_map(|ty| characteristic_def_id_of_type(ty)) .next(), - ty::TyFnDef(def_id, ..) | + ty::TyFnDef(def_id, _) | ty::TyClosure(def_id, _) => Some(def_id), ty::TyBool | diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 524cf57472bc8..a6c59d4c22354 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -875,13 +875,12 @@ define_maps! { <'tcx> /// for trans. This is also the only query that can fetch non-local MIR, at present. [] optimized_mir: Mir(DefId) -> &'tcx mir::Mir<'tcx>, - /// Records the type of each closure. The def ID is the ID of the + /// Type of each closure. The def ID is the ID of the /// expression defining the closure. [] closure_kind: ItemSignature(DefId) -> ty::ClosureKind, - /// Records the type of each closure. The def ID is the ID of the - /// expression defining the closure. - [] closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>, + /// The signature of functions and closures. + [] fn_sig: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>, /// Caches CoerceUnsized kinds for impls on custom types. [] coerce_unsized_info: ItemSignature(DefId) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 13e46a265c695..f4d0867d13000 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -206,7 +206,7 @@ impl AssociatedItem { // late-bound regions, and we don't want method signatures to show up // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound // regions just fine, showing `fn(&MyType)`. - format!("{}", tcx.type_of(self.def_id).fn_sig().skip_binder()) + format!("{}", tcx.fn_sig(self.def_id).skip_binder()) } ty::AssociatedKind::Type => format!("type {};", self.name.to_string()), ty::AssociatedKind::Const => { diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index d4f06a902eeaa..2e9780572c9b4 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -291,7 +291,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { if a.def_id != b.def_id { Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id))) } else { - let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?; + let substs = relate_substs(relation, None, a.substs, b.substs)?; Ok(ty::TraitRef { def_id: a.def_id, substs: substs }) } } @@ -308,7 +308,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { if a.def_id != b.def_id { Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id))) } else { - let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?; + let substs = relate_substs(relation, None, a.substs, b.substs)?; Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs }) } } @@ -440,13 +440,11 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, } } - (&ty::TyFnDef(a_def_id, a_substs, a_fty), - &ty::TyFnDef(b_def_id, b_substs, b_fty)) + (&ty::TyFnDef(a_def_id, a_substs), &ty::TyFnDef(b_def_id, b_substs)) if a_def_id == b_def_id => { - let substs = relate_substs(relation, None, a_substs, b_substs)?; - let fty = relation.relate(&a_fty, &b_fty)?; - Ok(tcx.mk_fn_def(a_def_id, substs, fty)) + let substs = relation.relate_item_substs(a_def_id, a_substs, b_substs)?; + Ok(tcx.mk_fn_def(a_def_id, substs)) } (&ty::TyFnPtr(a_fty), &ty::TyFnPtr(b_fty)) => diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 1e2689243903e..d05262965d7fd 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -531,10 +531,8 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyDynamic(ref trait_ty, ref region) => ty::TyDynamic(trait_ty.fold_with(folder), region.fold_with(folder)), ty::TyTuple(ts, defaulted) => ty::TyTuple(ts.fold_with(folder), defaulted), - ty::TyFnDef(def_id, substs, f) => { - ty::TyFnDef(def_id, - substs.fold_with(folder), - f.fold_with(folder)) + ty::TyFnDef(def_id, substs) => { + ty::TyFnDef(def_id, substs.fold_with(folder)) } ty::TyFnPtr(f) => ty::TyFnPtr(f.fold_with(folder)), ty::TyRef(ref r, tm) => { @@ -568,9 +566,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyDynamic(ref trait_ty, ref reg) => trait_ty.visit_with(visitor) || reg.visit_with(visitor), ty::TyTuple(ts, _) => ts.visit_with(visitor), - ty::TyFnDef(_, substs, ref f) => { - substs.visit_with(visitor) || f.visit_with(visitor) - } + ty::TyFnDef(_, substs) => substs.visit_with(visitor), ty::TyFnPtr(ref f) => f.visit_with(visitor), ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 6923a6d21d63f..ed3312d88a384 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use hir::map::DefPathHash; use middle::region; -use ty::subst::Substs; +use ty::subst::{Substs, Subst}; use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; use ty::{Slice, TyS}; use ty::subst::Kind; @@ -138,7 +138,7 @@ pub enum TypeVariants<'tcx> { /// The anonymous type of a function declaration/definition. Each /// function has a unique type. - TyFnDef(DefId, &'tcx Substs<'tcx>, PolyFnSig<'tcx>), + TyFnDef(DefId, &'tcx Substs<'tcx>), /// A pointer to a function. Written as `fn() -> i32`. TyFnPtr(PolyFnSig<'tcx>), @@ -1329,9 +1329,12 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn fn_sig(&self) -> PolyFnSig<'tcx> { + pub fn fn_sig(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> PolyFnSig<'tcx> { match self.sty { - TyFnDef(.., f) | TyFnPtr(f) => f, + TyFnDef(def_id, substs) => { + tcx.fn_sig(def_id).subst(tcx, substs) + } + TyFnPtr(f) => f, _ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self) } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 1bbc767348563..98ef7918fef82 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -679,7 +679,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyRef(_, m) => self.hash(m.mutbl), TyClosure(def_id, _) | TyAnon(def_id, _) | - TyFnDef(def_id, ..) => self.def_id(def_id), + TyFnDef(def_id, _) => self.def_id(def_id), TyAdt(d, _) => self.def_id(d.did), TyFnPtr(f) => { self.hash(f.unsafety()); diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index d7954953aba85..71844abfe534c 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -115,9 +115,8 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::TyTuple(ts, _) => { stack.extend(ts.iter().cloned().rev()); } - ty::TyFnDef(_, substs, ft) => { + ty::TyFnDef(_, substs) => { stack.extend(substs.types().rev()); - push_sig_subtypes(stack, ft); } ty::TyFnPtr(ft) => { push_sig_subtypes(stack, ft); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 1fa6357719666..eb6bffc29c561 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -753,8 +753,14 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { } write!(f, ")") } - TyFnDef(def_id, substs, ref bare_fn) => { - write!(f, "{} {{", bare_fn.0)?; + TyFnDef(def_id, substs) => { + ty::tls::with(|tcx| { + let mut sig = tcx.fn_sig(def_id); + if let Some(substs) = tcx.lift(&substs) { + sig = sig.subst(tcx, substs); + } + write!(f, "{} {{", sig.0) + })?; parameterized(f, substs, def_id, &[])?; write!(f, "}}") } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 2c55460fb301b..4bef191b113bd 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -161,18 +161,13 @@ fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, terminator: &'a Option>) -> Option<(&'a [mir::Operand<'tcx>], Span)> { if let Some(mir::Terminator { ref kind, source_info, .. }) = *terminator { - if let mir::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind - { - if let mir::Operand::Constant(ref func) = *oper - { - if let ty::TyFnDef(def_id, _, sig) = func.ty.sty - { - let abi = sig.abi(); + if let mir::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind { + if let mir::Operand::Constant(ref func) = *oper { + if let ty::TyFnDef(def_id, _) = func.ty.sty { + let abi = tcx.fn_sig(def_id).abi(); let name = tcx.item_name(def_id); - if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - if name == "rustc_peek" { - return Some((args, source_info.span)); - } + if abi == Abi::RustIntrinsic && name == "rustc_peek" { + return Some((args, source_info.span)); } } } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index d175920e8a6ba..0a966b0c17071 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -12,7 +12,7 @@ use eval; use rustc::middle::const_val::{ConstEvalErr, ConstVal}; use rustc::mir::{Field, BorrowKind, Mutability}; -use rustc::ty::{self, TyCtxt, AdtDef, Ty, TypeVariants, Region}; +use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; use rustc::hir::def::{Def, CtorKind}; @@ -549,8 +549,8 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { let adt_def = self.tcx.adt_def(enum_id); if adt_def.variants.len() > 1 { let substs = match ty.sty { - TypeVariants::TyAdt(_, substs) => substs, - TypeVariants::TyFnDef(_, substs, _) => substs, + ty::TyAdt(_, substs) | + ty::TyFnDef(_, substs) => substs, _ => bug!("inappropriate type for def: {:?}", ty.sty), }; PatternKind::Variant { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 9800012917c50..ad154f9b81531 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1154,24 +1154,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { if !def_id_is_transmute(cx, did) { return None; } - let typ = cx.tables.node_id_to_type(expr.id); - match typ.sty { - ty::TyFnDef(.., bare_fn) if bare_fn.abi() == RustIntrinsic => { - let from = bare_fn.inputs().skip_binder()[0]; - let to = *bare_fn.output().skip_binder(); - return Some((&from.sty, &to.sty)); - } - _ => (), - } + let sig = cx.tables.node_id_to_type(expr.id).fn_sig(cx.tcx); + let from = sig.inputs().skip_binder()[0]; + let to = *sig.output().skip_binder(); + return Some((&from.sty, &to.sty)); } None } fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { - match cx.tcx.type_of(def_id).sty { - ty::TyFnDef(.., bfty) if bfty.abi() == RustIntrinsic => (), - _ => return false, - } + cx.tcx.fn_sig(def_id).abi() == RustIntrinsic && cx.tcx.item_name(def_id) == "transmute" } } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 32bde42b5261f..ac3977bd216e7 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -659,7 +659,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) { let def_id = self.cx.tcx.hir.local_def_id(id); - let sig = self.cx.tcx.type_of(def_id).fn_sig(); + let sig = self.cx.tcx.fn_sig(def_id); let sig = self.cx.tcx.erase_late_bound_regions(&sig); for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index c49712086d52c..502eab44dac52 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -106,7 +106,7 @@ provide! { <'tcx> tcx, def_id, cdata, mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } typeck_tables_of => { cdata.item_body_tables(def_id.index, tcx) } closure_kind => { cdata.closure_kind(def_id.index) } - closure_type => { cdata.closure_ty(def_id.index, tcx) } + fn_sig => { cdata.fn_sig(def_id.index, tcx) } inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } is_const_fn => { cdata.is_const_fn(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 728ab30bb17dc..3e6d06ec86ff8 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1084,14 +1084,20 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn closure_ty(&self, - closure_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::PolyFnSig<'tcx> { - match self.entry(closure_id).kind { - EntryKind::Closure(data) => data.decode(self).ty.decode((self, tcx)), + pub fn fn_sig(&self, + id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> ty::PolyFnSig<'tcx> { + let sig = match self.entry(id).kind { + EntryKind::Fn(data) | + EntryKind::ForeignFn(data) => data.decode(self).sig, + EntryKind::Method(data) => data.decode(self).fn_data.sig, + EntryKind::Variant(data) | + EntryKind::Struct(data, _) => data.decode(self).ctor_sig.unwrap(), + EntryKind::Closure(data) => data.decode(self).sig, _ => bug!(), - } + }; + sig.decode((self, tcx)) } #[inline] diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 2a504c4c07794..e9701b95002d4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -16,6 +16,7 @@ use schema::*; use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary, EncodedMetadata, EncodedMetadataHashes, EncodedMetadataHash}; +use rustc::hir::def::CtorKind; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE}; use rustc::hir::map::definitions::{DefPathTable, GlobalMetaDataKind}; use rustc::ich::Fingerprint; @@ -499,6 +500,11 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ctor_kind: variant.ctor_kind, discr: variant.discr, struct_ctor: None, + ctor_sig: if variant.ctor_kind == CtorKind::Fn { + Some(self.lazy(&tcx.fn_sig(def_id))) + } else { + None + } }; let enum_id = tcx.hir.as_local_node_id(enum_did).unwrap(); @@ -518,7 +524,11 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + variances: if variant.ctor_kind == CtorKind::Fn { + self.encode_variances_of(def_id) + } else { + LazySeq::empty() + }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), @@ -617,6 +627,11 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ctor_kind: variant.ctor_kind, discr: variant.discr, struct_ctor: Some(def_id.index), + ctor_sig: if variant.ctor_kind == CtorKind::Fn { + Some(self.lazy(&tcx.fn_sig(def_id))) + } else { + None + } }; let struct_id = tcx.hir.as_local_node_id(adt_def_id).unwrap(); @@ -641,7 +656,11 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + variances: if variant.ctor_kind == CtorKind::Fn { + self.encode_variances_of(def_id) + } else { + LazySeq::empty() + }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), @@ -695,7 +714,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { }; FnData { constness: hir::Constness::NotConst, - arg_names: arg_names + arg_names: arg_names, + sig: self.lazy(&tcx.fn_sig(def_id)), } } else { bug!() @@ -732,7 +752,11 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } }, inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + variances: if trait_item.kind == ty::AssociatedKind::Method { + self.encode_variances_of(def_id) + } else { + LazySeq::empty() + }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), @@ -747,6 +771,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { debug!("IsolatedEncoder::encode_info_for_impl_item({:?})", def_id); + let tcx = self.tcx; + let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); let ast_item = self.tcx.hir.expect_impl_item(node_id); let impl_item = self.tcx.associated_item(def_id); @@ -768,6 +794,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { FnData { constness: sig.constness, arg_names: self.encode_fn_arg_names_for_body(body), + sig: self.lazy(&tcx.fn_sig(def_id)), } } else { bug!() @@ -806,7 +833,11 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + variances: if impl_item.kind == ty::AssociatedKind::Method { + self.encode_variances_of(def_id) + } else { + LazySeq::empty() + }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), @@ -881,6 +912,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let data = FnData { constness: constness, arg_names: self.encode_fn_arg_names_for_body(body), + sig: self.lazy(&tcx.fn_sig(def_id)), }; EntryKind::Fn(self.lazy(&data)) @@ -910,6 +942,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ctor_kind: variant.ctor_kind, discr: variant.discr, struct_ctor: struct_ctor, + ctor_sig: None, }), repr_options) } hir::ItemUnion(..) => { @@ -920,6 +953,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ctor_kind: variant.ctor_kind, discr: variant.discr, struct_ctor: None, + ctor_sig: None, }), repr_options) } hir::ItemDefaultImpl(..) => { @@ -1037,7 +1071,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) | - hir::ItemTrait(..) => self.encode_variances_of(def_id), + hir::ItemFn(..) => self.encode_variances_of(def_id), _ => LazySeq::empty(), }, generics: match item.node { @@ -1175,7 +1209,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let data = ClosureData { kind: tcx.closure_kind(def_id), - ty: self.lazy(&tcx.closure_type(def_id)), + sig: self.lazy(&tcx.fn_sig(def_id)), }; Entry { @@ -1363,6 +1397,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let data = FnData { constness: hir::Constness::NotConst, arg_names: self.encode_fn_arg_names(names), + sig: self.lazy(&tcx.fn_sig(def_id)), }; EntryKind::ForeignFn(self.lazy(&data)) } @@ -1381,7 +1416,10 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), - variances: LazySeq::empty(), + variances: match nitem.node { + hir::ForeignItemFn(..) => self.encode_variances_of(def_id), + _ => LazySeq::empty(), + }, generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 1337f90efa74d..9ef5b9408303d 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -343,18 +343,18 @@ pub enum EntryKind<'tcx> { Type, Enum(ReprOptions), Field, - Variant(Lazy), - Struct(Lazy, ReprOptions), - Union(Lazy, ReprOptions), - Fn(Lazy), - ForeignFn(Lazy), + Variant(Lazy>), + Struct(Lazy>, ReprOptions), + Union(Lazy>, ReprOptions), + Fn(Lazy>), + ForeignFn(Lazy>), Mod(Lazy), MacroDef(Lazy), Closure(Lazy>), Trait(Lazy>), Impl(Lazy>), DefaultImpl(Lazy>), - Method(Lazy), + Method(Lazy>), AssociatedType(AssociatedContainer), AssociatedConst(AssociatedContainer, u8), } @@ -439,27 +439,33 @@ pub struct MacroDef { impl_stable_hash_for!(struct MacroDef { body, legacy }); #[derive(RustcEncodable, RustcDecodable)] -pub struct FnData { +pub struct FnData<'tcx> { pub constness: hir::Constness, pub arg_names: LazySeq, + pub sig: Lazy>, } -impl_stable_hash_for!(struct FnData { constness, arg_names }); +impl_stable_hash_for!(struct FnData<'tcx> { constness, arg_names, sig }); #[derive(RustcEncodable, RustcDecodable)] -pub struct VariantData { +pub struct VariantData<'tcx> { pub ctor_kind: CtorKind, pub discr: ty::VariantDiscr, /// If this is a struct's only variant, this /// is the index of the "struct ctor" item. pub struct_ctor: Option, + + /// If this is a tuple struct or variant + /// ctor, this is its "function" signature. + pub ctor_sig: Option>>, } -impl_stable_hash_for!(struct VariantData { +impl_stable_hash_for!(struct VariantData<'tcx> { ctor_kind, discr, - struct_ctor + struct_ctor, + ctor_sig }); #[derive(RustcEncodable, RustcDecodable)] @@ -543,16 +549,16 @@ impl AssociatedContainer { } #[derive(RustcEncodable, RustcDecodable)] -pub struct MethodData { - pub fn_data: FnData, +pub struct MethodData<'tcx> { + pub fn_data: FnData<'tcx>, pub container: AssociatedContainer, pub has_self: bool, } -impl_stable_hash_for!(struct MethodData { fn_data, container, has_self }); +impl_stable_hash_for!(struct MethodData<'tcx> { fn_data, container, has_self }); #[derive(RustcEncodable, RustcDecodable)] pub struct ClosureData<'tcx> { pub kind: ty::ClosureKind, - pub ty: Lazy>, + pub sig: Lazy>, } -impl_stable_hash_for!(struct ClosureData<'tcx> { kind, ty }); +impl_stable_hash_for!(struct ClosureData<'tcx> { kind, sig }); diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index b7abc707a380d..326c1df69ebeb 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -205,11 +205,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // FIXME(canndrew): This is_never should probably be an is_uninhabited let diverges = expr.ty.is_never(); let intrinsic = match ty.sty { - ty::TyFnDef(def_id, _, ref f) if - f.abi() == Abi::RustIntrinsic || - f.abi() == Abi::PlatformIntrinsic => - { - Some(this.hir.tcx().item_name(def_id).as_str()) + ty::TyFnDef(def_id, _) => { + let f = ty.fn_sig(this.hir.tcx()); + if f.abi() == Abi::RustIntrinsic || + f.abi() == Abi::PlatformIntrinsic { + Some(this.hir.tcx().item_name(def_id).as_str()) + } else { + None + } } _ => None }; diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 474feefabbb88..0010f312ef985 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -19,7 +19,6 @@ use rustc::middle::const_val::ConstVal; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::cast::CastKind as TyCastKind; -use rustc::ty::subst::Subst; use rustc::hir; impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { @@ -586,7 +585,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }); Expr { temp_lifetime: temp_lifetime, - ty: cx.tcx.type_of(def_id).subst(cx.tcx, substs), + ty: cx.tcx().mk_fn_def(def_id, substs), span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 54779cbe30126..11ad5d1509d29 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -58,7 +58,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, // types in the MIR. They will be substituted again with // the param-substs, but because they are concrete, this // will not do any harm. - let sig = tcx.erase_late_bound_regions(&ty.fn_sig()); + let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx)); let arg_tys = sig.inputs(); build_call_shim( @@ -153,8 +153,8 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, } else { Substs::identity_for_item(tcx, def_id) }; - let fn_ty = tcx.type_of(def_id).subst(tcx, substs); - let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); + let sig = tcx.fn_sig(def_id).subst(tcx, substs); + let sig = tcx.erase_late_bound_regions(&sig); let span = tcx.def_span(def_id); let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }; @@ -276,8 +276,8 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, call_kind={:?}, untuple_args={:?})", def_id, rcvr_adjustment, call_kind, untuple_args); - let fn_ty = tcx.type_of(def_id); - let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); + let sig = tcx.fn_sig(def_id); + let sig = tcx.erase_late_bound_regions(&sig); let span = tcx.def_span(def_id); debug!("build_call_shim: sig={:?}", sig); @@ -409,11 +409,8 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, { let tcx = infcx.tcx; let def_id = tcx.hir.local_def_id(ctor_id); - let sig = match tcx.type_of(def_id).sty { - ty::TyFnDef(_, _, fty) => tcx.no_late_bound_regions(&fty) - .expect("LBR in ADT constructor signature"), - _ => bug!("unexpected type for ctor {:?}", def_id) - }; + let sig = tcx.no_late_bound_regions(&tcx.fn_sig(def_id)) + .expect("LBR in ADT constructor signature"); let sig = tcx.erase_regions(&sig); let (adt_def, substs) = match sig.output().sty { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 0ac35a5fdd472..5f80c7bee1478 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let terminator = bb_data.terminator(); if let TerminatorKind::Call { func: Operand::Constant(ref f), .. } = terminator.kind { - if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { + if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty { callsites.push_back(CallSite { callee: callee_def_id, substs: substs, @@ -131,7 +131,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let terminator = bb_data.terminator(); if let TerminatorKind::Call { func: Operand::Constant(ref f), .. } = terminator.kind { - if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { + if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty { // Don't inline the same function multiple times. if callsite.callee != callee_def_id { callsites.push_back(CallSite { @@ -270,8 +270,9 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } TerminatorKind::Call {func: Operand::Constant(ref f), .. } => { - if let ty::TyFnDef(.., f) = f.ty.sty { + if let ty::TyFnDef(def_id, _) = f.ty.sty { // Don't give intrinsics the extra penalty for calls + let f = tcx.fn_sig(def_id); if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { cost += INSTR_COST; } else { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 05a6cdd57ffce..91d6ce60b3904 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -750,8 +750,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { let fn_ty = func.ty(self.mir, self.tcx); let (is_shuffle, is_const_fn) = match fn_ty.sty { - ty::TyFnDef(def_id, _, f) => { - (f.abi() == Abi::PlatformIntrinsic && + ty::TyFnDef(def_id, _) => { + (self.tcx.fn_sig(def_id).abi() == Abi::PlatformIntrinsic && self.tcx.item_name(def_id).as_str().starts_with("simd_shuffle"), self.tcx.is_const_fn(def_id)) } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index efde39ad6a4c1..7e6fccf30192c 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -462,7 +462,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let func_ty = func.ty(mir, tcx); debug!("check_terminator: call, func_ty={:?}", func_ty); let sig = match func_ty.sty { - ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => sig, + ty::TyFnDef(..) | ty::TyFnPtr(_) => func_ty.fn_sig(tcx), _ => { span_mirbug!(self, term, "call to non-function {:?}", func_ty); return; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index fb7258d426622..9eb96fea52778 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -400,7 +400,13 @@ impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { } fn ty(&mut self) -> &mut Self { - self.ev.tcx.type_of(self.item_def_id).visit_with(self); + let ty = self.ev.tcx.type_of(self.item_def_id); + ty.visit_with(self); + if let ty::TyFnDef(def_id, _) = ty.sty { + if def_id == self.item_def_id { + self.ev.tcx.fn_sig(def_id).visit_with(self); + } + } self } @@ -910,7 +916,13 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { } fn ty(&mut self) -> &mut Self { - self.tcx.type_of(self.item_def_id).visit_with(self); + let ty = self.tcx.type_of(self.item_def_id); + ty.visit_with(self); + if let ty::TyFnDef(def_id, _) = ty.sty { + if def_id == self.item_def_id { + self.tcx.fn_sig(def_id).visit_with(self); + } + } self } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 8e14335ceacb9..10b66fb199108 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -154,6 +154,13 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert!(!item_type.has_erasable_regions()); hasher.visit_ty(item_type); + // If this is a function, we hash the signature as well. + // This is not *strictly* needed, but it may help in some + // situations, see the `run-make/a-b-a-linker-guard` test. + if let ty::TyFnDef(..) = item_type.sty { + item_type.fn_sig(tcx).visit_with(&mut hasher); + } + // also include any type parameters (for generic items) if let Some(substs) = substs { assert!(!substs.has_erasable_regions()); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index d723cf325718e..3c502eec549b2 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -587,7 +587,7 @@ fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, is_direct_call: bool, output: &mut Vec>) { - if let ty::TyFnDef(def_id, substs, _) = ty.sty { + if let ty::TyFnDef(def_id, substs) = ty.sty { let instance = monomorphize::resolve(scx, def_id, substs); visit_instance_use(scx, instance, is_direct_call, output); } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index a6f3fb709a01b..9b0803908b162 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -495,12 +495,12 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> ty::PolyFnSig<'tcx> { match ty.sty { - ty::TyFnDef(_, _, sig) => sig, + ty::TyFnDef(..) | // Shims currently have type TyFnPtr. Not sure this should remain. - ty::TyFnPtr(sig) => sig, + ty::TyFnPtr(_) => ty.fn_sig(ccx.tcx()), ty::TyClosure(def_id, substs) => { let tcx = ccx.tcx(); - let sig = tcx.closure_type(def_id).subst(tcx, substs.substs); + let sig = tcx.fn_sig(def_id).subst(tcx, substs.substs); let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); let env_ty = match tcx.closure_kind(def_id) { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 95ceec610eaa3..0cc1993601119 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -488,7 +488,6 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, debug!("type_metadata: {:?}", t); - let sty = &t.sty; let ptr_metadata = |ty: Ty<'tcx>| { match ty.sty { ty::TySlice(typ) => { @@ -518,7 +517,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } }; - let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty { + let MetadataCreationResult { metadata, already_stored_in_typemap } = match t.sty { ty::TyNever | ty::TyBool | ty::TyChar | @@ -557,10 +556,10 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Err(metadata) => return metadata, } } - ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { let fn_metadata = subroutine_type_metadata(cx, unique_type_id, - sig, + t.fn_sig(cx.tcx()), usage_site_span).metadata; match debug_context(cx).type_map .borrow() @@ -610,7 +609,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, usage_site_span).finalize(cx) } _ => { - bug!("debuginfo: unexpected type in type_metadata: {:?}", sty) + bug!("debuginfo: unexpected type in type_metadata: {:?}", t) } }; diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 13ff6646e6662..bfca4fec706ed 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -96,8 +96,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, push_type_params(cx, principal.substs, output); } }, - ty::TyFnDef(.., sig) | - ty::TyFnPtr(sig) => { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { + let sig = t.fn_sig(cx.tcx()); if sig.unsafety() == hir::Unsafety::Unsafe { output.push_str("unsafe "); } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index de908bb24a7ab..9956c28e64121 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -95,11 +95,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let ccx = bcx.ccx; let tcx = ccx.tcx(); - let (def_id, substs, sig) = match callee_ty.sty { - ty::TyFnDef(def_id, substs, sig) => (def_id, substs, sig), + let (def_id, substs) = match callee_ty.sty { + ty::TyFnDef(def_id, substs) => (def_id, substs), _ => bug!("expected fn item type, found {}", callee_ty) }; + let sig = callee_ty.fn_sig(tcx); let sig = tcx.erase_late_bound_regions_and_normalize(&sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); @@ -986,7 +987,7 @@ fn generic_simd_intrinsic<'a, 'tcx>( let tcx = bcx.tcx(); - let sig = tcx.erase_late_bound_regions_and_normalize(&callee_ty.fn_sig()); + let sig = tcx.erase_late_bound_regions_and_normalize(&callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); // every intrinsic takes a SIMD vector as its first argument diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 8863c7ffae6f4..16972a1b1ae24 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -404,20 +404,18 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.trans_operand(&bcx, func); - let (instance, mut llfn, sig) = match callee.ty.sty { - ty::TyFnDef(def_id, substs, sig) => { + let (instance, mut llfn) = match callee.ty.sty { + ty::TyFnDef(def_id, substs) => { (Some(monomorphize::resolve(bcx.ccx.shared(), def_id, substs)), - None, - sig) + None) } - ty::TyFnPtr(sig) => { - (None, - Some(callee.immediate()), - sig) + ty::TyFnPtr(_) => { + (None, Some(callee.immediate())) } _ => bug!("{} is not callable", callee.ty) }; let def = instance.map(|i| i.def); + let sig = callee.ty.fn_sig(bcx.tcx()); let sig = bcx.tcx().erase_late_bound_regions_and_normalize(&sig); let abi = sig.abi; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 16ef32ccf5777..fcb4b25e6fe88 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -334,7 +334,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let fn_ty = func.ty(self.mir, tcx); let fn_ty = self.monomorphize(&fn_ty); let (def_id, substs) = match fn_ty.sty { - ty::TyFnDef(def_id, substs, _) => (def_id, substs), + ty::TyFnDef(def_id, substs) => (def_id, substs), _ => span_bug!(span, "calling {:?} (of type {}) in constant", func, fn_ty) }; @@ -560,7 +560,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let val = match *kind { mir::CastKind::ReifyFnPointer => { match operand.ty.sty { - ty::TyFnDef(def_id, substs, _) => { + ty::TyFnDef(def_id, substs) => { callee::resolve_and_get_fn(self.ccx, def_id, substs) } _ => { @@ -579,7 +579,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { .find(|it| it.kind == ty::AssociatedKind::Method) .unwrap().def_id; // Now create its substs [Closure, Tuple] - let input = tcx.closure_type(def_id) + let input = tcx.fn_sig(def_id) .subst(tcx, substs.substs).input(0); let input = tcx.erase_late_bound_regions_and_normalize(&input); let substs = tcx.mk_substs([operand.ty, input] diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 61e537c9cc0c9..4bd5091a4f35f 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -180,7 +180,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let val = match *kind { mir::CastKind::ReifyFnPointer => { match operand.ty.sty { - ty::TyFnDef(def_id, substs, _) => { + ty::TyFnDef(def_id, substs) => { OperandValue::Immediate( callee::resolve_and_get_fn(bcx.ccx, def_id, substs)) } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index d27eeb2b64667..1f6a262162d39 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -40,7 +40,7 @@ fn fn_once_adapter_instance<'a, 'tcx>( let self_ty = tcx.mk_closure_from_closure_substs( closure_did, substs); - let sig = tcx.closure_type(closure_did).subst(tcx, substs.substs); + let sig = tcx.fn_sig(closure_did).subst(tcx, substs.substs); let sig = tcx.erase_late_bound_regions_and_normalize(&sig); assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs([ @@ -165,9 +165,11 @@ pub fn resolve<'a, 'tcx>( } else { let item_type = def_ty(scx, def_id, substs); let def = match item_type.sty { - ty::TyFnDef(_, _, f) if - f.abi() == Abi::RustIntrinsic || - f.abi() == Abi::PlatformIntrinsic => + ty::TyFnDef(..) if { + let f = item_type.fn_sig(scx.tcx()); + f.abi() == Abi::RustIntrinsic || + f.abi() == Abi::PlatformIntrinsic + } => { debug!(" => intrinsic"); ty::InstanceDef::Intrinsic(def_id) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 0dc2bc85e30e6..f59f6850da103 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -401,8 +401,9 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output); } }, - ty::TyFnDef(.., sig) | - ty::TyFnPtr(sig) => { + ty::TyFnDef(..) | + ty::TyFnPtr(_) => { + let sig = t.fn_sig(self.tcx); if sig.unsafety() == hir::Unsafety::Unsafe { output.push_str("unsafe "); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index bdd8169b84fe7..68726a7b1c4eb 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -619,7 +619,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Type check the path. let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); // Replace constructor type with constructed type for tuple struct patterns. - let pat_ty = pat_ty.fn_sig().output(); + let pat_ty = pat_ty.fn_sig(tcx).output(); let pat_ty = tcx.no_late_bound_regions(&pat_ty).expect("expected fn type"); self.demand_eqtype(pat.span, expected, pat_ty); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 385ed7eb0e384..a0801a7486654 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // haven't yet decided on whether the closure is fn vs // fnmut vs fnonce. If so, we have to defer further processing. if self.closure_kind(def_id).is_none() { - let closure_ty = self.closure_type(def_id).subst(self.tcx, substs.substs); + let closure_ty = self.fn_sig(def_id).subst(self.tcx, substs.substs); let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, &closure_ty) @@ -196,8 +196,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected: Expectation<'tcx>) -> Ty<'tcx> { let (fn_sig, def_span) = match callee_ty.sty { - ty::TyFnDef(def_id, .., sig) => { - (sig, self.tcx.hir.span_if_local(def_id)) + ty::TyFnDef(def_id, _) => { + (callee_ty.fn_sig(self.tcx), self.tcx.hir.span_if_local(def_id)) } ty::TyFnPtr(sig) => (sig, None), ref t => { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index ea08f1f624e67..46d304976dc63 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -356,8 +356,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (Some(t_from), Some(t_cast)) => (t_from, t_cast), // Function item types may need to be reified before casts. (None, Some(t_cast)) => { - if let ty::TyFnDef(.., f) = self.expr_ty.sty { + if let ty::TyFnDef(..) = self.expr_ty.sty { // Attempt a coercion to a fn pointer type. + let f = self.expr_ty.fn_sig(fcx.tcx); let res = fcx.try_coerce(self.expr, self.expr_ty, self.expr_diverges, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 30ac7b4bfb9be..17d0222371682 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -210,13 +210,13 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } match a.sty { - ty::TyFnDef(.., a_f) => { + ty::TyFnDef(..) => { // Function items are coercible to any closure // type; function pointers are not (that would // require double indirection). // Additionally, we permit coercion of function // items to drop the unsafe qualifier. - self.coerce_from_fn_item(a, a_f, b) + self.coerce_from_fn_item(a, b) } ty::TyFnPtr(a_f) => { // We permit coercion of fn pointers to drop the @@ -600,7 +600,6 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { fn coerce_from_fn_item(&self, a: Ty<'tcx>, - fn_ty_a: ty::PolyFnSig<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { //! Attempts to coerce from the type of a Rust function item @@ -612,9 +611,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { match b.sty { ty::TyFnPtr(_) => { - let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); - self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b, - simple(Adjust::ReifyFnPointer), simple(Adjust::ReifyFnPointer)) + let a_sig = a.fn_sig(self.tcx); + let InferOk { value: a_sig, mut obligations } = + self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig); + + let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig); + let InferOk { value, obligations: o2 } = + self.coerce_from_safe_fn(a_fn_pointer, a_sig, b, + simple(Adjust::ReifyFnPointer), simple(Adjust::ReifyFnPointer))?; + + obligations.extend(o2); + Ok(InferOk { value, obligations }) } _ => self.unify_and(a, b, identity), } @@ -639,7 +646,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // `extern "rust-call" fn((arg0,arg1,...)) -> _` // to // `fn(arg0,arg1,...) -> _` - let sig = self.closure_type(def_id_a).subst(self.tcx, substs_a.substs); + let sig = self.fn_sig(def_id_a).subst(self.tcx, substs_a.substs); let converted_sig = sig.map_bound(|s| { let params_iter = match s.inputs()[0].sty { ty::TyTuple(params, _) => { @@ -775,42 +782,41 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Special-case that coercion alone cannot handle: // Two function item types of differing IDs or Substs. - match (&prev_ty.sty, &new_ty.sty) { - (&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { - // The signature must always match. - let fty = self.at(cause, self.param_env) - .trace(prev_ty, new_ty) - .lub(&a_fty, &b_fty) - .map(|ok| self.register_infer_ok_obligations(ok))?; - - if a_def_id == b_def_id { - // Same function, maybe the parameters match. - let substs = self.commit_if_ok(|_| { - self.at(cause, self.param_env) - .trace(prev_ty, new_ty) - .lub(&a_substs, &b_substs) - .map(|ok| self.register_infer_ok_obligations(ok)) - }); - - if let Ok(substs) = substs { - // We have a LUB of prev_ty and new_ty, just return it. - return Ok(self.tcx.mk_fn_def(a_def_id, substs, fty)); - } - } + if let (&ty::TyFnDef(..), &ty::TyFnDef(..)) = (&prev_ty.sty, &new_ty.sty) { + // Don't reify if the function types have a LUB, i.e. they + // are the same function and their parameters have a LUB. + let lub_ty = self.commit_if_ok(|_| { + self.at(cause, self.param_env) + .lub(prev_ty, new_ty) + .map(|ok| self.register_infer_ok_obligations(ok)) + }); + + if lub_ty.is_ok() { + // We have a LUB of prev_ty and new_ty, just return it. + return lub_ty; + } - // Reify both sides and return the reified fn pointer type. - let fn_ptr = self.tcx.mk_fn_ptr(fty); - for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) { - // The only adjustment that can produce an fn item is - // `NeverToAny`, so this should always be valid. - self.apply_adjustments(expr, vec![Adjustment { - kind: Adjust::ReifyFnPointer, - target: fn_ptr - }]); - } - return Ok(fn_ptr); + // The signature must match. + let a_sig = prev_ty.fn_sig(self.tcx); + let a_sig = self.normalize_associated_types_in(new.span, &a_sig); + let b_sig = new_ty.fn_sig(self.tcx); + let b_sig = self.normalize_associated_types_in(new.span, &b_sig); + let sig = self.at(cause, self.param_env) + .trace(prev_ty, new_ty) + .lub(&a_sig, &b_sig) + .map(|ok| self.register_infer_ok_obligations(ok))?; + + // Reify both sides and return the reified fn pointer type. + let fn_ptr = self.tcx.mk_fn_ptr(sig); + for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) { + // The only adjustment that can produce an fn item is + // `NeverToAny`, so this should always be valid. + self.apply_adjustments(expr, vec![Adjustment { + kind: Adjust::ReifyFnPointer, + target: fn_ptr + }]); } - _ => {} + return Ok(fn_ptr); } let mut coerce = Coerce::new(self, cause.clone()); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 29742469f84d9..fd5147d76e8fd 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -256,17 +256,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Compute skolemized form of impl and trait method tys. let tcx = infcx.tcx; - let m_sig = |method: &ty::AssociatedItem| { - match tcx.type_of(method.def_id).sty { - ty::TyFnDef(_, _, f) => f, - _ => bug!() - } - }; - let (impl_sig, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, infer::HigherRankedType, - &m_sig(impl_m)); + &tcx.fn_sig(impl_m.def_id)); let impl_sig = inh.normalize_associated_types_in(impl_m_span, impl_m_node_id, @@ -277,7 +270,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_sig = inh.liberate_late_bound_regions( impl_m.def_id, - &m_sig(trait_m)); + &tcx.fn_sig(trait_m.def_id)); let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs); let trait_sig = @@ -507,8 +500,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::ImplContainer(_) => impl_trait_ref.self_ty(), ty::TraitContainer(_) => tcx.mk_self_type() }; - let method_ty = tcx.type_of(method.def_id); - let self_arg_ty = *method_ty.fn_sig().input(0).skip_binder(); + let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder(); match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) { ExplicitSelf::ByValue => "self".to_string(), ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_string(), @@ -637,14 +629,8 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_m: &ty::AssociatedItem, trait_item_span: Option) -> Result<(), ErrorReported> { - let m_fty = |method: &ty::AssociatedItem| { - match tcx.type_of(method.def_id).sty { - ty::TyFnDef(_, _, f) => f, - _ => bug!() - } - }; - let impl_m_fty = m_fty(impl_m); - let trait_m_fty = m_fty(trait_m); + let impl_m_fty = tcx.fn_sig(impl_m.def_id); + let trait_m_fty = tcx.fn_sig(trait_m.def_id); let trait_number_args = trait_m_fty.inputs().skip_binder().len(); let impl_number_args = impl_m_fty.inputs().skip_binder().len(); if trait_number_args != impl_number_args { diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 1b6f96cf65137..287c591c1183d 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -143,12 +143,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn has_no_input_arg(&self, method: &AssociatedItem) -> bool { match method.def() { Def::Method(def_id) => { - match self.tcx.type_of(def_id).sty { - ty::TypeVariants::TyFnDef(_, _, sig) => { - sig.inputs().skip_binder().len() == 1 - } - _ => false, - } + self.tcx.fn_sig(def_id).inputs().skip_binder().len() == 1 } _ => false, } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 4d9f50b0fc0c9..3acfbd1d84403 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -13,7 +13,6 @@ use intrinsics; use rustc::traits::{ObligationCause, ObligationCauseCode}; -use rustc::ty::subst::Substs; use rustc::ty::{self, TyCtxt, Ty}; use rustc::util::nodemap::FxHashMap; use require_same_types; @@ -35,22 +34,22 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output: Ty<'tcx>) { let def_id = tcx.hir.local_def_id(it.id); - let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.types.re_erased, - |def, _| tcx.mk_param_from_def(def)); + match it.node { + hir::ForeignItemFn(..) => {} + _ => { + struct_span_err!(tcx.sess, it.span, E0619, + "intrinsic must be a function") + .span_label(it.span, "expected a function") + .emit(); + return; + } + } - let fty = tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig( - inputs.into_iter(), - output, - false, - hir::Unsafety::Unsafe, - abi - ))); let i_n_tps = tcx.generics_of(def_id).types.len(); if i_n_tps != n_tps { let span = match it.node { hir::ForeignItemFn(_, _, ref generics) => generics.span, - hir::ForeignItemStatic(..) => it.span + _ => bug!() }; struct_span_err!(tcx.sess, span, E0094, @@ -59,14 +58,18 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, i_n_tps, n_tps) .span_label(span, format!("expected {} type parameter", n_tps)) .emit(); - } else { - require_same_types(tcx, - &ObligationCause::new(it.span, - it.id, - ObligationCauseCode::IntrinsicType), - tcx.type_of(def_id), - fty); + return; } + + let fty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig( + inputs.into_iter(), + output, + false, + hir::Unsafety::Unsafe, + abi + ))); + let cause = ObligationCause::new(it.span, it.id, ObligationCauseCode::IntrinsicType); + require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(def_id)), fty); } /// Remember to add all intrinsics here, in librustc_trans/trans/intrinsic.rs, @@ -376,7 +379,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut structural_to_nomimal = FxHashMap(); - let sig = tcx.type_of(def_id).fn_sig(); + let sig = tcx.fn_sig(def_id); let sig = tcx.no_late_bound_regions(&sig).unwrap(); if intr.inputs.len() != sig.inputs().len() { span_err!(tcx.sess, it.span, E0444, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 36bd665738951..209245187b13f 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -375,7 +375,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { debug!("method_predicates after subst = {:?}", method_predicates); - let sig = self.tcx.type_of(def_id).fn_sig(); + let sig = self.tcx.fn_sig(def_id); // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 73c1215f275fb..4f4169ac93d1b 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -235,7 +235,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let fn_sig = tcx.type_of(def_id).fn_sig(); + let fn_sig = tcx.fn_sig(def_id); let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &fn_sig).0; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 2518a1739f73e..ee9a347ae9511 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -673,7 +673,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { expected: ty::Ty<'tcx>) -> bool { match method.def() { Def::Method(def_id) => { - let fty = self.tcx.type_of(def_id).fn_sig(); + let fty = self.tcx.fn_sig(def_id); self.probe(|_| { let substs = self.fresh_substs_for_item(self.span, method.def_id); let output = fty.output().subst(self.tcx, substs); @@ -1288,7 +1288,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { - let self_ty = self.tcx.type_of(method).fn_sig().input(0); + let self_ty = self.tcx.fn_sig(method).input(0); debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", impl_ty, self_ty, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2bf24d5b3504c..701de029b2bd5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -718,20 +718,12 @@ pub fn provide(providers: &mut Providers) { typeck_item_bodies, typeck_tables_of, has_typeck_tables, - closure_type, closure_kind, adt_destructor, ..*providers }; } -fn closure_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> ty::PolyFnSig<'tcx> { - let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); - tcx.typeck_tables_of(def_id).closure_tys[&node_id] -} - fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureKind { @@ -844,7 +836,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Inherited::build(tcx, def_id).enter(|inh| { let param_env = tcx.param_env(def_id); let fcx = if let Some(decl) = fn_decl { - let fn_sig = tcx.type_of(def_id).fn_sig(); + let fn_sig = tcx.fn_sig(def_id); check_abi(tcx, span, fn_sig.abi()); @@ -2173,7 +2165,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> ty::TypeAndMut<'tcx> { // extract method return type, which will be &T; - // all LB regions should have been instantiated during method lookup let ret_ty = method.sig.output(); // method returns &T, but the type as visible to user is T, so deref @@ -2580,8 +2571,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => { variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); } - ty::TyFnDef(.., f) => { - let ptr_ty = self.tcx.mk_fn_ptr(f); + ty::TyFnDef(..) => { + let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty); variadic_error(tcx.sess, arg.span, arg_ty, &format!("{}", ptr_ty)); } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 26f708e934562..cbda1227742ca 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -177,12 +177,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } ty::AssociatedKind::Method => { reject_shadowing_type_parameters(fcx.tcx, item.def_id); - let method_ty = fcx.tcx.type_of(item.def_id); - let method_ty = fcx.normalize_associated_types_in(span, &method_ty); + let sig = fcx.tcx.fn_sig(item.def_id); + let sig = fcx.normalize_associated_types_in(span, &sig); let predicates = fcx.tcx.predicates_of(item.def_id) .instantiate_identity(fcx.tcx); let predicates = fcx.normalize_associated_types_in(span, &predicates); - let sig = method_ty.fn_sig(); this.check_fn_or_method(fcx, span, sig, &predicates, item.def_id, &mut implied_bounds); let sig_if_method = sig_if_method.expect("bad signature for method"); @@ -331,9 +330,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fn check_item_fn(&mut self, item: &hir::Item) { self.for_item(item).with_fcx(|fcx, this| { let def_id = fcx.tcx.hir.local_def_id(item.id); - let ty = fcx.tcx.type_of(def_id); - let item_ty = fcx.normalize_associated_types_in(item.span, &ty); - let sig = item_ty.fn_sig(); + let sig = fcx.tcx.fn_sig(def_id); + let sig = fcx.normalize_associated_types_in(item.span, &sig); let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx); let predicates = fcx.normalize_associated_types_in(item.span, &predicates); @@ -461,9 +459,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let span = method_sig.decl.inputs[0].span; - let method_ty = fcx.tcx.type_of(method.def_id); - let fty = fcx.normalize_associated_types_in(span, &method_ty); - let sig = fcx.liberate_late_bound_regions(method.def_id, &fty.fn_sig()); + let sig = fcx.tcx.fn_sig(method.def_id); + let sig = fcx.normalize_associated_types_in(span, &sig); + let sig = fcx.liberate_late_bound_regions(method.def_id, &sig); debug!("check_method_receiver: sig={:?}", sig); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fb3bcd31e21fc..fd6dda5ccf4a7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -97,6 +97,7 @@ pub fn provide(providers: &mut Providers) { type_param_predicates, trait_def, adt_def, + fn_sig, impl_trait_ref, impl_polarity, is_foreign_item, @@ -447,6 +448,9 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); + if let hir::ForeignItemFn(..) = item.node { + tcx.fn_sig(def_id); + } } } hir::ItemEnum(ref enum_definition, _) => { @@ -497,6 +501,9 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); + if let hir::ItemFn(..) = it.node { + tcx.fn_sig(def_id); + } } } } @@ -511,6 +518,9 @@ fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: ast: hir::TraitItemKind::Type(_, Some(_)) | hir::TraitItemKind::Method(..) => { tcx.type_of(def_id); + if let hir::TraitItemKind::Method(..) = trait_item.node { + tcx.fn_sig(def_id); + } } hir::TraitItemKind::Type(_, None) => {} @@ -524,6 +534,9 @@ fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_id: ast::N tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); + if let hir::ImplItemKind::Method(..) = tcx.hir.expect_impl_item(impl_item_id).node { + tcx.fn_sig(def_id); + } } fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -963,10 +976,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match tcx.hir.get(node_id) { NodeTraitItem(item) => { match item.node { - TraitItemKind::Method(ref sig, _) => { - let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl); + TraitItemKind::Method(..) => { let substs = Substs::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs, fty) + tcx.mk_fn_def(def_id, substs) } TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty), @@ -978,10 +990,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeImplItem(item) => { match item.node { - ImplItemKind::Method(ref sig, _) => { - let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl); + ImplItemKind::Method(..) => { let substs = Substs::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs, fty) + tcx.mk_fn_def(def_id, substs) } ImplItemKind::Const(ref ty, _) => icx.to_ty(ty), ImplItemKind::Type(ref ty) => { @@ -1001,10 +1012,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemTy(ref t, _) | ItemImpl(.., ref t, _) => { icx.to_ty(t) } - ItemFn(ref decl, unsafety, _, abi, _, _) => { - let tofd = AstConv::ty_of_fn(&icx, unsafety, abi, &decl); + ItemFn(..) => { let substs = Substs::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs, tofd) + tcx.mk_fn_def(def_id, substs) } ItemEnum(..) | ItemStruct(..) | @@ -1029,11 +1039,10 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } NodeForeignItem(foreign_item) => { - let abi = tcx.hir.get_foreign_abi(node_id); - match foreign_item.node { - ForeignItemFn(ref fn_decl, _, _) => { - compute_type_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) + ForeignItemFn(..) => { + let substs = Substs::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) } ForeignItemStatic(ref t, _) => icx.to_ty(t) } @@ -1041,21 +1050,13 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeStructCtor(&ref def) | NodeVariant(&Spanned { node: hir::Variant_ { data: ref def, .. }, .. }) => { - let ty = tcx.type_of(tcx.hir.get_parent_did(node_id)); match *def { - VariantData::Unit(..) | VariantData::Struct(..) => ty, - VariantData::Tuple(ref fields, _) => { - let inputs = fields.iter().map(|f| { - tcx.type_of(tcx.hir.local_def_id(f.id)) - }); + VariantData::Unit(..) | VariantData::Struct(..) => { + tcx.type_of(tcx.hir.get_parent_did(node_id)) + } + VariantData::Tuple(..) => { let substs = Substs::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig( - inputs, - ty, - false, - hir::Unsafety::Normal, - abi::Abi::Rust - ))) + tcx.mk_fn_def(def_id, substs) } } } @@ -1105,6 +1106,58 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> ty::PolyFnSig<'tcx> { + use rustc::hir::map::*; + use rustc::hir::*; + + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + + let icx = ItemCtxt::new(tcx, def_id); + + match tcx.hir.get(node_id) { + NodeTraitItem(&hir::TraitItem { node: TraitItemKind::Method(ref sig, _), .. }) | + NodeImplItem(&hir::ImplItem { node: ImplItemKind::Method(ref sig, _), .. }) => { + AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl) + } + + NodeItem(&hir::Item { node: ItemFn(ref decl, unsafety, _, abi, _, _), .. }) => { + AstConv::ty_of_fn(&icx, unsafety, abi, decl) + } + + NodeForeignItem(&hir::ForeignItem { node: ForeignItemFn(ref fn_decl, _, _), .. }) => { + let abi = tcx.hir.get_foreign_abi(node_id); + compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) + } + + NodeStructCtor(&VariantData::Tuple(ref fields, _)) | + NodeVariant(&Spanned { node: hir::Variant_ { + data: VariantData::Tuple(ref fields, _), .. + }, .. }) => { + let ty = tcx.type_of(tcx.hir.get_parent_did(node_id)); + let inputs = fields.iter().map(|f| { + tcx.type_of(tcx.hir.local_def_id(f.id)) + }); + ty::Binder(tcx.mk_fn_sig( + inputs, + ty, + false, + hir::Unsafety::Normal, + abi::Abi::Rust + )) + } + + NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => { + tcx.typeck_tables_of(def_id).closure_tys[&node_id] + } + + x => { + bug!("unexpected sort of node in fn_sig(): {:?}", x); + } + } +} + fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option> { @@ -1502,12 +1555,12 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, } } -fn compute_type_of_foreign_fn_decl<'a, 'tcx>( +fn compute_sig_of_foreign_fn_decl<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, decl: &hir::FnDecl, abi: abi::Abi) - -> Ty<'tcx> + -> ty::PolyFnSig<'tcx> { let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), hir::Unsafety::Unsafe, abi, decl); @@ -1533,8 +1586,7 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( } } - let substs = Substs::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs, fty) + fty } fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index b2fa2cc7c61d2..bf5adc8644d51 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4736,4 +4736,5 @@ register_diagnostics! { E0568, // auto-traits can not have predicates, E0588, // packed struct cannot transitively contain a `[repr(align)]` struct E0592, // duplicate definitions with name `{}` + E0619, // intrinsic must be a function } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 9e99af633d517..519e1ca6e5a3c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -198,22 +198,21 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } _ => () } - let substs = tcx.intern_substs(&[]); - let se_ty = tcx.mk_fn_def(main_def_id, substs, - ty::Binder(tcx.mk_fn_sig( + let se_ty = tcx.mk_fn_ptr(ty::Binder( + tcx.mk_fn_sig( iter::empty(), tcx.mk_nil(), false, hir::Unsafety::Normal, Abi::Rust - )) - ); + ) + )); require_same_types( tcx, &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType), se_ty, - main_t); + tcx.mk_fn_ptr(tcx.fn_sig(main_def_id))); } _ => { span_bug!(main_span, @@ -248,9 +247,8 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => () } - let substs = tcx.intern_substs(&[]); - let se_ty = tcx.mk_fn_def(start_def_id, substs, - ty::Binder(tcx.mk_fn_sig( + let se_ty = tcx.mk_fn_ptr(ty::Binder( + tcx.mk_fn_sig( [ tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8)) @@ -259,14 +257,14 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, false, hir::Unsafety::Normal, Abi::Rust - )) - ); + ) + )); require_same_types( tcx, &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType), se_ty, - start_t); + tcx.mk_fn_ptr(tcx.fn_sig(start_def_id))); } _ => { span_bug!(start_span, diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index c434edb1c31ab..f4963619370e4 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -14,11 +14,9 @@ //! We walk the set of items and, for each member, generate new constraints. use hir::def_id::DefId; -use middle::resolve_lifetime as rl; use rustc::dep_graph::{AssertDepGraphSafe, DepKind}; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::hir::map as hir_map; use syntax::ast; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -61,10 +59,10 @@ pub struct Constraint<'a> { /// } /// /// then while we are visiting `Bar`, the `CurrentItem` would have -/// the def-id and generics of `Foo`. -pub struct CurrentItem<'a> { +/// the def-id and the start of `Foo`'s inferreds. +pub struct CurrentItem { def_id: DefId, - generics: &'a ty::Generics, + inferred_start: InferredIndex, } pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>) @@ -91,8 +89,59 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>) impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { + match item.node { + hir::ItemStruct(ref struct_def, _) | + hir::ItemUnion(ref struct_def, _) => { + self.visit_node_helper(item.id); + + if let hir::VariantData::Tuple(..) = *struct_def { + self.visit_node_helper(struct_def.id()); + } + } + + hir::ItemEnum(ref enum_def, _) => { + self.visit_node_helper(item.id); + + for variant in &enum_def.variants { + if let hir::VariantData::Tuple(..) = variant.node.data { + self.visit_node_helper(variant.node.data.id()); + } + } + } + + hir::ItemFn(..) => { + self.visit_node_helper(item.id); + } + + hir::ItemForeignMod(ref foreign_mod) => { + for foreign_item in &foreign_mod.items { + if let hir::ForeignItemFn(..) = foreign_item.node { + self.visit_node_helper(foreign_item.id); + } + } + } + + _ => {} + } + } + + fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + if let hir::TraitItemKind::Method(..) = trait_item.node { + self.visit_node_helper(trait_item.id); + } + } + + fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { + if let hir::ImplItemKind::Method(..) = impl_item.node { + self.visit_node_helper(impl_item.id); + } + } +} + +impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { + fn visit_node_helper(&mut self, id: ast::NodeId) { let tcx = self.terms_cx.tcx; - let def_id = tcx.hir.local_def_id(item.id); + let def_id = tcx.hir.local_def_id(id); // Encapsulate constructing the constraints into a task we can // reference later. This can go away once the red-green @@ -100,20 +149,11 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { // // See README.md for a detailed discussion // on dep-graph management. - match item.node { - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemUnion(..) => { - let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); - tcx.dep_graph.with_task(dep_node, - AssertDepGraphSafe(self), - def_id, - visit_item_task); - } - _ => { - // Nothing to do here, skip the task. - } - } + let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); + tcx.dep_graph.with_task(dep_node, + AssertDepGraphSafe(self), + def_id, + visit_item_task); fn visit_item_task<'a, 'tcx>(ccx: AssertDepGraphSafe<&mut ConstraintContext<'a, 'tcx>>, def_id: DefId) @@ -122,197 +162,57 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { } } - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { - } - - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { - } -} - -/// Is `param_id` a lifetime according to `map`? -fn is_lifetime(map: &hir_map::Map, param_id: ast::NodeId) -> bool { - match map.find(param_id) { - Some(hir_map::NodeLifetime(..)) => true, - _ => false, - } -} - -impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.terms_cx.tcx } fn build_constraints_for_item(&mut self, def_id: DefId) { let tcx = self.tcx(); - let id = self.tcx().hir.as_local_node_id(def_id).unwrap(); - let item = tcx.hir.expect_item(id); - debug!("visit_item item={}", tcx.hir.node_to_string(item.id)); + debug!("build_constraints_for_item({})", tcx.item_path_str(def_id)); - match item.node { - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemUnion(..) => { - let generics = tcx.generics_of(def_id); - let current_item = &CurrentItem { def_id, generics }; + // Skip items with no generics - there's nothing to infer in them. + if tcx.generics_of(def_id).count() == 0 { + return; + } + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let inferred_start = self.terms_cx.inferred_starts[&id]; + let current_item = &CurrentItem { def_id, inferred_start }; + match tcx.type_of(def_id).sty { + ty::TyAdt(def, _) => { // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion // in comment at top of module. // // self.add_constraints_from_generics(generics); - for field in tcx.adt_def(def_id).all_fields() { + for field in def.all_fields() { self.add_constraints_from_ty(current_item, tcx.type_of(field.did), self.covariant); } } - hir::ItemTrait(..) | - hir::ItemExternCrate(_) | - hir::ItemUse(..) | - hir::ItemStatic(..) | - hir::ItemConst(..) | - hir::ItemFn(..) | - hir::ItemMod(..) | - hir::ItemForeignMod(..) | - hir::ItemGlobalAsm(..) | - hir::ItemTy(..) | - hir::ItemImpl(..) | - hir::ItemDefaultImpl(..) => { - span_bug!(item.span, "`build_constraints_for_item` invoked for non-type-def"); + ty::TyFnDef(..) => { + self.add_constraints_from_sig(current_item, + tcx.fn_sig(def_id), + self.covariant); } - } - } - - /// Load the generics for another item, adding a corresponding - /// relation into the dependencies to indicate that the variance - /// for `current` relies on `def_id`. - fn read_generics(&mut self, current: &CurrentItem, def_id: DefId) -> &'tcx ty::Generics { - let generics = self.tcx().generics_of(def_id); - if self.tcx().dep_graph.is_fully_enabled() { - self.dependencies.add(current.def_id, def_id); - } - generics - } - fn opt_inferred_index(&self, param_id: ast::NodeId) -> Option<&InferredIndex> { - self.terms_cx.inferred_map.get(¶m_id) - } - - fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId { - let tcx = self.terms_cx.tcx; - assert!(is_lifetime(&tcx.hir, param_id)); - match tcx.named_region_map.defs.get(¶m_id) { - Some(&rl::Region::EarlyBound(_, lifetime_decl_id)) => lifetime_decl_id, - Some(_) => bug!("should not encounter non early-bound cases"), - - // The lookup should only fail when `param_id` is - // itself a lifetime binding: use it as the decl_id. - None => param_id, - } - - } - - /// Is `param_id` a type parameter for which we infer variance? - fn is_to_be_inferred(&self, param_id: ast::NodeId) -> bool { - let result = self.terms_cx.inferred_map.contains_key(¶m_id); - - // To safe-guard against invalid inferred_map constructions, - // double-check if variance is inferred at some use of a type - // parameter (by inspecting parent of its binding declaration - // to see if it is introduced by a type or by a fn/impl). - - let check_result = |this: &ConstraintContext| -> bool { - let tcx = this.terms_cx.tcx; - let decl_id = this.find_binding_for_lifetime(param_id); - // Currently only called on lifetimes; double-checking that. - assert!(is_lifetime(&tcx.hir, param_id)); - let parent_id = tcx.hir.get_parent(decl_id); - let parent = tcx.hir - .find(parent_id) - .unwrap_or_else(|| bug!("tcx.hir missing entry for id: {}", parent_id)); - - let is_inferred; - macro_rules! cannot_happen { () => { { - bug!("invalid parent: {} for {}", - tcx.hir.node_to_string(parent_id), - tcx.hir.node_to_string(param_id)); - } } } - - match parent { - hir_map::NodeItem(p) => { - match p.node { - hir::ItemTy(..) | - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemUnion(..) | - hir::ItemTrait(..) => is_inferred = true, - hir::ItemFn(..) => is_inferred = false, - _ => cannot_happen!(), - } - } - hir_map::NodeTraitItem(..) => is_inferred = false, - hir_map::NodeImplItem(..) => is_inferred = false, - _ => cannot_happen!(), - } - - return is_inferred; - }; - - assert_eq!(result, check_result(self)); - - return result; - } - - /// Returns a variance term representing the declared variance of the type/region parameter - /// with the given id. - fn declared_variance(&self, - param_def_id: DefId, - item_def_id: DefId, - index: usize) - -> VarianceTermPtr<'a> { - assert_eq!(param_def_id.krate, item_def_id.krate); - - if let Some(param_node_id) = self.tcx().hir.as_local_node_id(param_def_id) { - // Parameter on an item defined within current crate: - // variance not yet inferred, so return a symbolic - // variance. - if let Some(&InferredIndex(index)) = self.opt_inferred_index(param_node_id) { - self.terms_cx.inferred_infos[index].term - } else { - // If there is no inferred entry for a type parameter, - // it must be declared on a (locally defiend) trait -- they don't - // get inferreds because they are always invariant. - if cfg!(debug_assertions) { - let item_node_id = self.tcx().hir.as_local_node_id(item_def_id).unwrap(); - let item = self.tcx().hir.expect_item(item_node_id); - let success = match item.node { - hir::ItemTrait(..) => true, - _ => false, - }; - if !success { - bug!("parameter {:?} has no inferred, but declared on non-trait: {:?}", - item_def_id, - item); - } - } - self.invariant + _ => { + span_bug!(tcx.def_span(def_id), + "`build_constraints_for_item` unsupported for this item"); } - } else { - // Parameter on an item defined within another crate: - // variance already inferred, just look it up. - let variances = self.tcx().variances_of(item_def_id); - self.constant_term(variances[index]) } } fn add_constraint(&mut self, - InferredIndex(index): InferredIndex, + current: &CurrentItem, + index: u32, variance: VarianceTermPtr<'a>) { debug!("add_constraint(index={}, variance={:?})", index, variance); self.constraints.push(Constraint { - inferred: InferredIndex(index), + inferred: InferredIndex(current.inferred_start.0 + index as usize), variance: variance, }); } @@ -354,15 +254,26 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}", trait_ref, variance); + self.add_constraints_from_invariant_substs(current, trait_ref.substs, variance); + } - let trait_generics = self.tcx().generics_of(trait_ref.def_id); + fn add_constraints_from_invariant_substs(&mut self, + current: &CurrentItem, + substs: &Substs<'tcx>, + variance: VarianceTermPtr<'a>) { + debug!("add_constraints_from_invariant_substs: substs={:?} variance={:?}", + substs, + variance); - self.add_constraints_from_substs(current, - trait_ref.def_id, - &trait_generics.types, - &trait_generics.regions, - trait_ref.substs, - variance); + // Trait are always invariant so we can take advantage of that. + let variance_i = self.invariant(variance); + for ty in substs.types() { + self.add_constraints_from_ty(current, ty, variance_i); + } + + for region in substs.regions() { + self.add_constraints_from_region(current, region, variance_i); + } } /// Adds constraints appropriate for an instance of `ty` appearing @@ -382,8 +293,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // leaf type -- noop } - ty::TyClosure(..) | - ty::TyAnon(..) => { + ty::TyFnDef(..) | + ty::TyClosure(..) => { bug!("Unexpected closure type in variance computation"); } @@ -409,26 +320,15 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyAdt(def, substs) => { - let adt_generics = self.read_generics(current, def.did); - - self.add_constraints_from_substs(current, - def.did, - &adt_generics.types, - &adt_generics.regions, - substs, - variance); + self.add_constraints_from_substs(current, def.did, substs, variance); } ty::TyProjection(ref data) => { - let trait_ref = &data.trait_ref; - let trait_generics = self.tcx().generics_of(trait_ref.def_id); - - self.add_constraints_from_substs(current, - trait_ref.def_id, - &trait_generics.types, - &trait_generics.regions, - trait_ref.substs, - variance); + self.add_constraints_from_trait_ref(current, data.trait_ref, variance); + } + + ty::TyAnon(_, substs) => { + self.add_constraints_from_invariant_substs(current, substs, variance); } ty::TyDynamic(ref data, r) => { @@ -447,26 +347,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyParam(ref data) => { - assert_eq!(current.generics.parent, None); - let mut i = data.idx as usize; - if !current.generics.has_self || i > 0 { - i -= current.generics.regions.len(); - } - let def_id = current.generics.types[i].def_id; - let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap(); - match self.terms_cx.inferred_map.get(&node_id) { - Some(&index) => { - self.add_constraint(index, variance); - } - None => { - // We do not infer variance for type parameters - // declared on methods. They will not be present - // in the inferred_map. - } - } + self.add_constraint(current, data.idx, variance); } - ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => { self.add_constraints_from_sig(current, sig, variance); } @@ -489,8 +372,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { fn add_constraints_from_substs(&mut self, current: &CurrentItem, def_id: DefId, - type_param_defs: &[ty::TypeParameterDef], - region_param_defs: &[ty::RegionParameterDef], substs: &Substs<'tcx>, variance: VarianceTermPtr<'a>) { debug!("add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})", @@ -498,21 +379,45 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { substs, variance); - for p in type_param_defs { - let variance_decl = self.declared_variance(p.def_id, def_id, p.index as usize); + // We don't record `inferred_starts` entries for empty generics. + if substs.is_empty() { + return; + } + + // Add a corresponding relation into the dependencies to + // indicate that the variance for `current` relies on `def_id`. + if self.tcx().dep_graph.is_fully_enabled() { + self.dependencies.add(current.def_id, def_id); + } + + let (local, remote) = if let Some(id) = self.tcx().hir.as_local_node_id(def_id) { + (Some(self.terms_cx.inferred_starts[&id]), None) + } else { + (None, Some(self.tcx().variances_of(def_id))) + }; + + for (i, k) in substs.iter().enumerate() { + let variance_decl = if let Some(InferredIndex(start)) = local { + // Parameter on an item defined within current crate: + // variance not yet inferred, so return a symbolic + // variance. + self.terms_cx.inferred_terms[start + i] + } else { + // Parameter on an item defined within another crate: + // variance already inferred, just look it up. + self.constant_term(remote.as_ref().unwrap()[i]) + }; let variance_i = self.xform(variance, variance_decl); - let substs_ty = substs.type_for_def(p); debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}", variance_decl, variance_i); - self.add_constraints_from_ty(current, substs_ty, variance_i); - } - - for p in region_param_defs { - let variance_decl = self.declared_variance(p.def_id, def_id, p.index as usize); - let variance_i = self.xform(variance, variance_decl); - let substs_r = substs.region_for_def(p); - self.add_constraints_from_region(current, substs_r, variance_i); + if let Some(ty) = k.as_type() { + self.add_constraints_from_ty(current, ty, variance_i); + } else if let Some(r) = k.as_region() { + self.add_constraints_from_region(current, r, variance_i); + } else { + bug!(); + } } } @@ -537,21 +442,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { variance: VarianceTermPtr<'a>) { match *region { ty::ReEarlyBound(ref data) => { - assert_eq!(current.generics.parent, None); - let i = data.index as usize - current.generics.has_self as usize; - let def_id = current.generics.regions[i].def_id; - let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap(); - if self.is_to_be_inferred(node_id) { - let &index = self.opt_inferred_index(node_id).unwrap(); - self.add_constraint(index, variance); - } + self.add_constraint(current, data.index, variance); } ty::ReStatic => {} ty::ReLateBound(..) => { - // We do not infer variance for region parameters on - // methods or in fn types. + // Late-bound regions do not get substituted the same + // way early-bound regions do, so we skip them here. } ty::ReFree(..) | diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index 8f9f40ca40b03..7a9f35545e2f3 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -54,45 +54,63 @@ fn crate_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) -> Rc> { - let item_id = tcx.hir.as_local_node_id(item_def_id).expect("expected local def-id"); - let item = tcx.hir.expect_item(item_id); - match item.node { - hir::ItemTrait(..) => { - // Traits are always invariant. - let generics = tcx.generics_of(item_def_id); - assert!(generics.parent.is_none()); - Rc::new(vec![ty::Variance::Invariant; generics.count()]) - } + let id = tcx.hir.as_local_node_id(item_def_id).expect("expected local def-id"); + let unsupported = || { + // Variance not relevant. + span_bug!(tcx.hir.span(id), "asked to compute variance for wrong kind of item") + }; + match tcx.hir.get(id) { + hir::map::NodeItem(item) => match item.node { + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemFn(..) => {} - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemUnion(..) => { - // Everything else must be inferred. + _ => unsupported() + }, - // Lacking red/green, we read the variances for all items here - // but ignore the dependencies, then re-synthesize the ones we need. - let crate_map = tcx.dep_graph.with_ignore(|| tcx.crate_variances(LOCAL_CRATE)); - let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); - tcx.dep_graph.read(dep_node); - for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) { - if dep_def_id.is_local() { - let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); - tcx.dep_graph.read(dep_node); - } else { - let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVariances); - tcx.dep_graph.read(dep_node); - } - } - - crate_map.variances.get(&item_def_id) - .unwrap_or(&crate_map.empty_variance) - .clone() - } + hir::map::NodeTraitItem(item) => match item.node { + hir::TraitItemKind::Method(..) => {} + + _ => unsupported() + }, + + hir::map::NodeImplItem(item) => match item.node { + hir::ImplItemKind::Method(..) => {} + + _ => unsupported() + }, + + hir::map::NodeForeignItem(item) => match item.node { + hir::ForeignItemFn(..) => {} - _ => { - // Variance not relevant. - span_bug!(item.span, "asked to compute variance for wrong kind of item") + _ => unsupported() + }, + + hir::map::NodeVariant(_) | hir::map::NodeStructCtor(_) => {} + + _ => unsupported() + } + + // Everything else must be inferred. + + // Lacking red/green, we read the variances for all items here + // but ignore the dependencies, then re-synthesize the ones we need. + let crate_map = tcx.dep_graph.with_ignore(|| tcx.crate_variances(LOCAL_CRATE)); + let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); + tcx.dep_graph.read(dep_node); + for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) { + if dep_def_id.is_local() { + let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); + tcx.dep_graph.read(dep_node); + } else { + let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVariances); + tcx.dep_graph.read(dep_node); } } + + crate_map.variances.get(&item_def_id) + .unwrap_or(&crate_map.empty_variance) + .clone() } diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index af8ad491ec00e..495eb95419a90 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -36,15 +36,18 @@ struct SolveContext<'a, 'tcx: 'a> { pub fn solve_constraints(constraints_cx: ConstraintContext) -> ty::CrateVariancesMap { let ConstraintContext { terms_cx, dependencies, constraints, .. } = constraints_cx; - let solutions = terms_cx.inferred_infos - .iter() - .map(|ii| ii.initial_variance) - .collect(); + let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()]; + for &(id, ref variances) in &terms_cx.lang_items { + let InferredIndex(start) = terms_cx.inferred_starts[&id]; + for (i, &variance) in variances.iter().enumerate() { + solutions[start + i] = variance; + } + } let mut solutions_cx = SolveContext { - terms_cx: terms_cx, - constraints: constraints, - solutions: solutions, + terms_cx, + constraints, + solutions, }; solutions_cx.solve(); let variances = solutions_cx.create_map(); @@ -71,12 +74,9 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { let old_value = self.solutions[inferred]; let new_value = glb(variance, old_value); if old_value != new_value { - debug!("Updating inferred {} (node {}) \ + debug!("Updating inferred {} \ from {:?} to {:?} due to {:?}", inferred, - self.terms_cx - .inferred_infos[inferred] - .param_id, old_value, new_value, term); @@ -89,49 +89,28 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { } fn create_map(&self) -> FxHashMap>> { - // Collect all the variances for a particular item and stick - // them into the variance map. We rely on the fact that we - // generate all the inferreds for a particular item - // consecutively (that is, we collect solutions for an item - // until we see a new item id, and we assume (1) the solutions - // are in the same order as the type parameters were declared - // and (2) all solutions or a given item appear before a new - // item id). - let tcx = self.terms_cx.tcx; - let mut map = FxHashMap(); - let solutions = &self.solutions; - let inferred_infos = &self.terms_cx.inferred_infos; - let mut index = 0; - let num_inferred = self.terms_cx.num_inferred(); - while index < num_inferred { - let item_id = inferred_infos[index].item_id; - - let mut item_variances = vec![]; - - while index < num_inferred && inferred_infos[index].item_id == item_id { - let info = &inferred_infos[index]; - let variance = solutions[index]; - debug!("Index {} Info {} Variance {:?}", - index, - info.index, - variance); - - assert_eq!(item_variances.len(), info.index); - item_variances.push(variance); - index += 1; - } + self.terms_cx.inferred_starts.iter().map(|(&id, &InferredIndex(start))| { + let def_id = tcx.hir.local_def_id(id); + let generics = tcx.generics_of(def_id); - debug!("item_id={} item_variances={:?}", item_id, item_variances); + let mut variances = solutions[start..start+generics.count()].to_vec(); - let item_def_id = tcx.hir.local_def_id(item_id); + debug!("id={} variances={:?}", id, variances); - map.insert(item_def_id, Rc::new(item_variances)); - } + // Functions can have unused type parameters: make those invariant. + if let ty::TyFnDef(..) = tcx.type_of(def_id).sty { + for variance in &mut variances { + if *variance == ty::Bivariant { + *variance = ty::Invariant; + } + } + } - map + (def_id, Rc::new(variances)) + }).collect() } fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance { diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index ad787c57e76f2..38457146a9714 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -22,7 +22,6 @@ use arena::TypedArena; use rustc::ty::{self, TyCtxt}; use std::fmt; -use std::rc::Rc; use syntax::ast; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -63,31 +62,17 @@ pub struct TermsContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub arena: &'a TypedArena>, - pub empty_variances: Rc>, - // For marker types, UnsafeCell, and other lang items where // variance is hardcoded, records the item-id and the hardcoded // variance. pub lang_items: Vec<(ast::NodeId, Vec)>, - // Maps from the node id of a type/generic parameter to the - // corresponding inferred index. - pub inferred_map: NodeMap, - - // Maps from an InferredIndex to the info for that variable. - pub inferred_infos: Vec>, -} - -pub struct InferredInfo<'a> { - pub item_id: ast::NodeId, - pub index: usize, - pub param_id: ast::NodeId, - pub term: VarianceTermPtr<'a>, + // Maps from the node id of an item to the first inferred index + // used for its type & region parameters. + pub inferred_starts: NodeMap, - // Initial value to use for this parameter when inferring - // variance. For most parameters, this is Bivariant. But for lang - // items and input type parameters on traits, it is different. - pub initial_variance: ty::Variance, + // Maps from an InferredIndex to the term for that variable. + pub inferred_terms: Vec>, } pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -96,14 +81,10 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx> let mut terms_cx = TermsContext { tcx: tcx, arena: arena, - inferred_map: NodeMap(), - inferred_infos: Vec::new(), + inferred_starts: NodeMap(), + inferred_terms: vec![], lang_items: lang_items(tcx), - - // cache and share the variance struct used for items with - // no type/region parameters - empty_variances: Rc::new(vec![]), }; // See README.md for a discussion on dep-graph management. @@ -135,67 +116,28 @@ fn lang_items(tcx: TyCtxt) -> Vec<(ast::NodeId, Vec)> { } impl<'a, 'tcx> TermsContext<'a, 'tcx> { - fn add_inferreds_for_item(&mut self, - item_id: ast::NodeId, - generics: &hir::Generics) { - //! Add "inferreds" for the generic parameters declared on this - //! item. This has a lot of annoying parameters because we are - //! trying to drive this from the AST, rather than the - //! ty::Generics, so that we can get span info -- but this - //! means we must accommodate syntactic distinctions. - //! + fn add_inferreds_for_item(&mut self, id: ast::NodeId) { + let tcx = self.tcx; + let def_id = tcx.hir.local_def_id(id); + let count = tcx.generics_of(def_id).count(); - // NB: In the code below for writing the results back into the - // `CrateVariancesMap`, we rely on the fact that all inferreds - // for a particular item are assigned continuous indices. - - for (p, i) in generics.lifetimes.iter().zip(0..) { - let id = p.lifetime.id; - self.add_inferred(item_id, i, id); - } - - for (p, i) in generics.ty_params.iter().zip(generics.lifetimes.len()..) { - self.add_inferred(item_id, i, p.id); + if count == 0 { + return; } - } - fn add_inferred(&mut self, item_id: ast::NodeId, index: usize, param_id: ast::NodeId) { - let inf_index = InferredIndex(self.inferred_infos.len()); - let term = self.arena.alloc(InferredTerm(inf_index)); - let initial_variance = self.pick_initial_variance(item_id, index); - self.inferred_infos.push(InferredInfo { - item_id: item_id, - index: index, - param_id: param_id, - term: term, - initial_variance: initial_variance, - }); - let newly_added = self.inferred_map.insert(param_id, inf_index).is_none(); + // Record the start of this item's inferreds. + let start = self.inferred_terms.len(); + let newly_added = self.inferred_starts.insert(id, InferredIndex(start)).is_none(); assert!(newly_added); - debug!("add_inferred(item_path={}, \ - item_id={}, \ - index={}, \ - param_id={}, \ - inf_index={:?}, \ - initial_variance={:?})", - self.tcx.item_path_str(self.tcx.hir.local_def_id(item_id)), - item_id, - index, - param_id, - inf_index, - initial_variance); - } - - fn pick_initial_variance(&self, item_id: ast::NodeId, index: usize) -> ty::Variance { - match self.lang_items.iter().find(|&&(n, _)| n == item_id) { - Some(&(_, ref variances)) => variances[index], - None => ty::Bivariant, - } - } + // NB: In the code below for writing the results back into the + // `CrateVariancesMap`, we rely on the fact that all inferreds + // for a particular item are assigned continuous indices. - pub fn num_inferred(&self) -> usize { - self.inferred_infos.len() + let arena = self.arena; + self.inferred_terms.extend((start..start+count).map(|i| { + &*arena.alloc(InferredTerm(InferredIndex(i))) + })); } } @@ -205,30 +147,50 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { self.tcx.hir.node_to_string(item.id)); match item.node { - hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) | - hir::ItemUnion(_, ref generics) => { - self.add_inferreds_for_item(item.id, generics); + hir::ItemStruct(ref struct_def, _) | + hir::ItemUnion(ref struct_def, _) => { + self.add_inferreds_for_item(item.id); + + if let hir::VariantData::Tuple(..) = *struct_def { + self.add_inferreds_for_item(struct_def.id()); + } + } + + hir::ItemEnum(ref enum_def, _) => { + self.add_inferreds_for_item(item.id); + + for variant in &enum_def.variants { + if let hir::VariantData::Tuple(..) = variant.node.data { + self.add_inferreds_for_item(variant.node.data.id()); + } + } + } + + hir::ItemFn(..) => { + self.add_inferreds_for_item(item.id); } - hir::ItemTrait(..) | - hir::ItemExternCrate(_) | - hir::ItemUse(..) | - hir::ItemDefaultImpl(..) | - hir::ItemImpl(..) | - hir::ItemStatic(..) | - hir::ItemConst(..) | - hir::ItemFn(..) | - hir::ItemMod(..) | - hir::ItemForeignMod(..) | - hir::ItemGlobalAsm(..) | - hir::ItemTy(..) => {} + hir::ItemForeignMod(ref foreign_mod) => { + for foreign_item in &foreign_mod.items { + if let hir::ForeignItemFn(..) = foreign_item.node { + self.add_inferreds_for_item(foreign_item.id); + } + } + } + + _ => {} } } - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { + fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + if let hir::TraitItemKind::Method(..) = trait_item.node { + self.add_inferreds_for_item(trait_item.id); + } } - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { + if let hir::ImplItemKind::Method(..) = impl_item.node { + self.add_inferreds_for_item(impl_item.id); + } } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index aeade47048223..fa5a999adf196 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -149,7 +149,7 @@ pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { } fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { - let sig = cx.tcx.type_of(did).fn_sig(); + let sig = cx.tcx.fn_sig(did); let constness = if cx.tcx.is_const_fn(did) { hir::Constness::Const diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8fc8ccd0cfd92..478e2fc5085d1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1367,7 +1367,7 @@ impl<'tcx> Clean for ty::AssociatedItem { ty::AssociatedKind::Method => { let generics = (cx.tcx.generics_of(self.def_id), &cx.tcx.predicates_of(self.def_id)).clean(cx); - let sig = cx.tcx.type_of(self.def_id).fn_sig(); + let sig = cx.tcx.fn_sig(self.def_id); let mut decl = (self.def_id, sig).clean(cx); if self.method_has_self_argument { @@ -1842,17 +1842,21 @@ impl<'tcx> Clean for ty::Ty<'tcx> { mutability: mt.mutbl.clean(cx), type_: box mt.ty.clean(cx), }, - ty::TyFnDef(.., sig) | - ty::TyFnPtr(sig) => BareFunction(box BareFunctionDecl { - unsafety: sig.unsafety(), - generics: Generics { - lifetimes: Vec::new(), - type_params: Vec::new(), - where_predicates: Vec::new() - }, - decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx), - abi: sig.abi(), - }), + ty::TyFnDef(..) | + ty::TyFnPtr(_) => { + let ty = cx.tcx.lift(self).unwrap(); + let sig = ty.fn_sig(cx.tcx); + BareFunction(box BareFunctionDecl { + unsafety: sig.unsafety(), + generics: Generics { + lifetimes: Vec::new(), + type_params: Vec::new(), + where_predicates: Vec::new() + }, + decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx), + abi: sig.abi(), + }) + } ty::TyAdt(def, substs) => { let did = def.did; let kind = match def.adt_kind() { diff --git a/src/test/compile-fail/associated-types-path-2.rs b/src/test/compile-fail/associated-types-path-2.rs index cdb7dff692c14..d62f6b0f1a371 100644 --- a/src/test/compile-fail/associated-types-path-2.rs +++ b/src/test/compile-fail/associated-types-path-2.rs @@ -38,11 +38,13 @@ pub fn f1_int_uint() { pub fn f1_uint_uint() { f1(2u32, 4u32); //~^ ERROR `u32: Foo` is not satisfied + //~| ERROR `u32: Foo` is not satisfied } pub fn f1_uint_int() { f1(2u32, 4i32); //~^ ERROR `u32: Foo` is not satisfied + //~| ERROR `u32: Foo` is not satisfied } pub fn f2_int() { diff --git a/src/test/compile-fail/invalid-intrinsic.rs b/src/test/compile-fail/invalid-intrinsic.rs index 2aa2546cb9fe1..c42d78c323e3c 100644 --- a/src/test/compile-fail/invalid-intrinsic.rs +++ b/src/test/compile-fail/invalid-intrinsic.rs @@ -11,6 +11,6 @@ #![feature(intrinsics)] extern "rust-intrinsic" { pub static breakpoint : unsafe extern "rust-intrinsic" fn(); - //~^ ERROR intrinsic has wrong type + //~^ ERROR intrinsic must be a function } -fn main() { unsafe { breakpoint(); } } \ No newline at end of file +fn main() { unsafe { breakpoint(); } } diff --git a/src/test/compile-fail/on-unimplemented/multiple-impls.rs b/src/test/compile-fail/on-unimplemented/multiple-impls.rs index 0df8c41ffe1a8..15375936b898c 100644 --- a/src/test/compile-fail/on-unimplemented/multiple-impls.rs +++ b/src/test/compile-fail/on-unimplemented/multiple-impls.rs @@ -44,12 +44,18 @@ fn main() { //~^ ERROR E0277 //~| NOTE trait message //~| NOTE required by + //~| ERROR E0277 + //~| NOTE trait message Index::index(&[] as &[i32], Foo(2u32)); //~^ ERROR E0277 //~| NOTE on impl for Foo //~| NOTE required by + //~| ERROR E0277 + //~| NOTE on impl for Foo Index::index(&[] as &[i32], Bar(2u32)); //~^ ERROR E0277 //~| NOTE on impl for Bar //~| NOTE required by + //~| ERROR E0277 + //~| NOTE on impl for Bar } diff --git a/src/test/compile-fail/on-unimplemented/on-impl.rs b/src/test/compile-fail/on-unimplemented/on-impl.rs index 79021cd03ccc1..66d612baab4e8 100644 --- a/src/test/compile-fail/on-unimplemented/on-impl.rs +++ b/src/test/compile-fail/on-unimplemented/on-impl.rs @@ -33,4 +33,6 @@ fn main() { //~^ ERROR E0277 //~| NOTE a usize is required //~| NOTE required by + //~| ERROR E0277 + //~| NOTE a usize is required } diff --git a/src/test/compile-fail/variance-region-bounds.rs b/src/test/compile-fail/variance-region-bounds.rs deleted file mode 100644 index 41d204a541b5a..0000000000000 --- a/src/test/compile-fail/variance-region-bounds.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Check that `T:'a` is contravariant in T. - -#![feature(rustc_attrs)] - -#[rustc_variance] -trait Foo: 'static { //~ ERROR [o] -} - -#[rustc_variance] -trait Bar { //~ ERROR [o, o] - fn do_it(&self) - where T: 'static; -} - -fn main() { } diff --git a/src/test/compile-fail/variance-trait-bounds.rs b/src/test/compile-fail/variance-trait-bounds.rs index 58fb785c48ca7..9b88e38e08554 100644 --- a/src/test/compile-fail/variance-trait-bounds.rs +++ b/src/test/compile-fail/variance-trait-bounds.rs @@ -14,13 +14,11 @@ // Check that bounds on type parameters (other than `Self`) do not // influence variance. -#[rustc_variance] -trait Getter { //~ ERROR [o, o] +trait Getter { fn get(&self) -> T; } -#[rustc_variance] -trait Setter { //~ ERROR [o, o] +trait Setter { fn get(&self, T); } @@ -34,20 +32,6 @@ enum TestEnum> { //~ ERROR [*, +] Foo(T) } -#[rustc_variance] -trait TestTrait> { //~ ERROR [o, o, o] - fn getter(&self, u: U) -> T; -} - -#[rustc_variance] -trait TestTrait2 : Getter { //~ ERROR [o, o] -} - -#[rustc_variance] -trait TestTrait3 { //~ ERROR [o, o] - fn getter>(&self); -} - #[rustc_variance] struct TestContraStruct> { //~ ERROR [*, +] t: T diff --git a/src/test/compile-fail/variance-types-bounds.rs b/src/test/compile-fail/variance-types-bounds.rs index 2df94cc907a9c..5075dd2ceedc0 100644 --- a/src/test/compile-fail/variance-types-bounds.rs +++ b/src/test/compile-fail/variance-types-bounds.rs @@ -36,37 +36,14 @@ struct TestIndirect2 { //~ ERROR [o, o] m: TestMut } -#[rustc_variance] -trait Getter { //~ ERROR [o, o] +trait Getter { fn get(&self) -> A; } -#[rustc_variance] -trait Setter { //~ ERROR [o, o] - fn set(&mut self, a: A); -} - -#[rustc_variance] -trait GetterSetter { //~ ERROR [o, o] - fn get(&self) -> A; +trait Setter { fn set(&mut self, a: A); } -#[rustc_variance] -trait GetterInTypeBound { //~ ERROR [o, o] - // Here, the use of `A` in the method bound *does* affect - // variance. Think of it as if the method requested a dictionary - // for `T:Getter`. Since this dictionary is an input, it is - // contravariant, and the Getter is covariant w/r/t A, yielding an - // overall contravariant result. - fn do_it>(&self); -} - -#[rustc_variance] -trait SetterInTypeBound { //~ ERROR [o, o] - fn do_it>(&self); -} - #[rustc_variance] struct TestObject { //~ ERROR [o, o] n: Box+Send>,