diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index b1d009146473..6d8558211818 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -676,8 +676,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { let tcx = self.infcx.tcx; value.fold_with(&mut BottomUpFolder { tcx, - reg_op: |reg| reg, - fldop: |ty| { + ty_op: |ty| { if let ty::Opaque(def_id, substs) = ty.sty { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose @@ -776,6 +775,8 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { ty }, + lt_op: |lt| lt, + ct_op: |ct| ct, }) } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 7f58a436fcf0..afd94757b232 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -193,29 +193,37 @@ pub trait TypeVisitor<'tcx> : Sized { /////////////////////////////////////////////////////////////////////////// // Some sample folders -pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G> +pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G, H> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, + H: FnMut(&'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx>, { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, - pub fldop: F, - pub reg_op: G, + pub ty_op: F, + pub lt_op: G, + pub ct_op: H, } -impl<'a, 'gcx, 'tcx, F, G> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G> +impl<'a, 'gcx, 'tcx, F, G, H> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G, H> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, + H: FnMut(&'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx>, { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - let t1 = ty.super_fold_with(self); - (self.fldop)(t1) + let t = ty.super_fold_with(self); + (self.ty_op)(t) } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { let r = r.super_fold_with(self); - (self.reg_op)(r) + (self.lt_op)(r) + } + + fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + let c = c.super_fold_with(self); + (self.ct_op)(c) } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 37be1c3b5b7f..8ee30c0d2d31 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -616,7 +616,7 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( let mut substituted_predicates = Vec::new(); ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: fcx.tcx, - fldop: |ty| { + ty_op: |ty| { if let ty::Opaque(def_id, substs) = ty.sty { trace!("check_existential_types: opaque_ty, {:?}, {:?}", def_id, substs); let generics = tcx.generics_of(def_id); @@ -739,7 +739,8 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( } // if let Opaque ty }, - reg_op: |reg| reg, + lt_op: |lt| lt, + ct_op: |ct| ct, }); substituted_predicates } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 80da3fd97512..d16d69e92332 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -11,7 +11,8 @@ use rustc::infer::InferCtxt; use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; use rustc::ty::subst::UnpackedKind; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, Const, LazyConst}; +use rustc::mir::interpret::ConstValue; use rustc::util::nodemap::DefIdSet; use rustc_data_structures::sync::Lrc; use std::mem; @@ -488,7 +489,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // figures out the concrete type with `U`, but the stored type is with `T` instantiated_ty.fold_with(&mut BottomUpFolder { tcx: self.tcx().global_tcx(), - fldop: |ty| { + ty_op: |ty| { trace!("checking type {:?}", ty); // find a type parameter if let ty::Param(..) = ty.sty { @@ -520,7 +521,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } ty }, - reg_op: |region| { + lt_op: |region| { match region { // ignore static regions ty::ReStatic => region, @@ -564,6 +565,41 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } }, + ct_op: |ct| { + trace!("checking const {:?}", ct); + // find a const parameter + if let LazyConst::Evaluated(Const { ty, val }) = ct { + if let ConstValue::Param(..) = val { + // look it up in the substitution list + assert_eq!(opaque_defn.substs.len(), generics.params.len()); + for (subst, param) in opaque_defn.substs.iter() + .zip(&generics.params) { + if let UnpackedKind::Const(subst) = subst.unpack() { + if subst == ct { + // found it in the substitution list, replace with the + // parameter from the existential type + return self.tcx() + .global_tcx() + .mk_const_param(param.index, param.name, ty); + } + } + } + self.tcx() + .sess + .struct_span_err( + span, + &format!( + "const parameter `{}` is part of concrete type but not \ + used in parameter list for existential type", + ct, + ), + ) + .emit(); + return self.tcx().types.ct_err; + } + } + ct + } }) };