From 62f23c2b0b66fdda31ff03cc688d8baa5759cec0 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:09:29 +0000 Subject: [PATCH 01/34] Add Const generic param to ty Co-Authored-By: Gabriel Smith --- src/librustc/ty/mod.rs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1f897d29a1eb8..bd3dd78c9bb67 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -837,7 +837,8 @@ pub enum GenericParamDefKind { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: Option, - } + }, + Const, } #[derive(Clone, RustcEncodable, RustcDecodable)] @@ -880,6 +881,7 @@ impl GenericParamDef { pub struct GenericParamCount { pub lifetimes: usize, pub types: usize, + pub consts: usize, } /// Information about the formal type/lifetime parameters associated @@ -915,6 +917,7 @@ impl<'a, 'gcx, 'tcx> Generics { match param.kind { GenericParamDefKind::Lifetime => own_counts.lifetimes += 1, GenericParamDefKind::Type { .. } => own_counts.types += 1, + GenericParamDefKind::Const => own_counts.consts += 1, }; } @@ -924,7 +927,7 @@ impl<'a, 'gcx, 'tcx> Generics { pub fn requires_monomorphization(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { for param in &self.params { match param.kind { - GenericParamDefKind::Type { .. } => return true, + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => return true, GenericParamDefKind::Lifetime => {} } } @@ -944,7 +947,7 @@ impl<'a, 'gcx, 'tcx> Generics { if let Some(index) = param.index.checked_sub(self.parent_count as u32) { let param = &self.params[index as usize]; match param.kind { - ty::GenericParamDefKind::Lifetime => param, + GenericParamDefKind::Lifetime => param, _ => bug!("expected lifetime parameter, but found another generic parameter") } } else { @@ -961,7 +964,7 @@ impl<'a, 'gcx, 'tcx> Generics { if let Some(index) = param.idx.checked_sub(self.parent_count as u32) { let param = &self.params[index as usize]; match param.kind { - ty::GenericParamDefKind::Type {..} => param, + GenericParamDefKind::Type { .. } => param, _ => bug!("expected type parameter, but found another generic parameter") } } else { @@ -969,6 +972,23 @@ impl<'a, 'gcx, 'tcx> Generics { .type_param(param, tcx) } } + + /// Returns the `ConstParameterDef` associated with this `ParamConst`. + pub fn const_param(&'tcx self, + param: &ParamConst, + tcx: TyCtxt<'a, 'gcx, 'tcx>) + -> &GenericParamDef { + if let Some(index) = param.index.checked_sub(self.parent_count as u32) { + let param = &self.params[index as usize]; + match param.kind { + GenericParamDefKind::Const => param, + _ => bug!("expected const parameter, but found another generic parameter") + } + } else { + tcx.generics_of(self.parent.expect("parent_count>0 but no parent?")) + .const_param(param, tcx) + } + } } /// Bounds on generics. From 11c31bb1d390c2a32e7546ab303835bfa1d48b6a Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:09:52 +0000 Subject: [PATCH 02/34] Add ParamConst Co-Authored-By: Gabriel Smith --- src/librustc/ty/sty.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 3fd2e38a3d3e5..2f77ad2f18036 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1061,6 +1061,26 @@ impl<'a, 'gcx, 'tcx> ParamTy { } } +#[derive(Copy, Clone, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)] +pub struct ParamConst { + pub index: u32, + pub name: InternedString, +} + +impl<'a, 'gcx, 'tcx> ParamConst { + pub fn new(index: u32, name: InternedString) -> ParamConst { + ParamConst { index, name } + } + + pub fn for_def(def: &ty::GenericParamDef) -> ParamConst { + ParamConst::new(def.index, def.name) + } + + pub fn to_const(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> &'tcx LazyConst<'tcx> { + tcx.mk_const_param(self.index, self.name, ty) + } +} + /// A [De Bruijn index][dbi] is a standard means of representing /// regions (and perhaps later types) in a higher-ranked setting. In /// particular, imagine a type like this: From a36d386c6d08b6afbaf8316242218d9644b2ab82 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:10:03 +0000 Subject: [PATCH 03/34] Add ConstVid Co-Authored-By: Gabriel Smith --- src/librustc/ty/sty.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 2f77ad2f18036..afe3dc2300a8b 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -16,6 +16,7 @@ use crate::mir::interpret::{Scalar, Pointer}; use smallvec::SmallVec; use std::iter; use std::cmp::Ordering; +use std::marker::PhantomData; use rustc_target::spec::abi; use syntax::ast::{self, Ident}; use syntax::symbol::{keywords, InternedString}; @@ -1249,6 +1250,12 @@ pub struct TyVid { pub index: u32, } +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +pub struct ConstVid<'tcx> { + pub index: u32, + pub phantom: PhantomData<&'tcx ()>, +} + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct IntVid { pub index: u32, From 8cbbbaae6c1956d2c070e7f7447a9478adbf0dcd Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:10:11 +0000 Subject: [PATCH 04/34] Add InferConst Co-Authored-By: Gabriel Smith --- src/librustc/ty/sty.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index afe3dc2300a8b..3b58cca38dd11 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2228,3 +2228,14 @@ impl<'tcx> Const<'tcx> { } impl<'tcx> serialize::UseSpecializedDecodable for &'tcx LazyConst<'tcx> {} + +/// An inference variable for a const, for use in const generics. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)] +pub enum InferConst<'tcx> { + /// Infer the value of the const. + Var(ConstVid<'tcx>), + /// A fresh const variable. See `infer::freshen` for more details. + Fresh(u32), + /// Canonicalized const variable, used only when preparing a trait query. + Canonical(DebruijnIndex, BoundVar), +} From 386e9fbda225bd04039a47caad9138983faff18c Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:10:22 +0000 Subject: [PATCH 05/34] Add type_flags helper methods to consts Co-Authored-By: Gabriel Smith --- src/librustc/ty/sty.rs | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 3b58cca38dd11..1aa4ca7ff97ab 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2110,6 +2110,22 @@ impl<'tcx> LazyConst<'tcx> { pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 { self.assert_usize(tcx).expect("expected `LazyConst` to contain a usize") } + + pub fn type_flags(&self) -> TypeFlags { + // FIXME(const_generics): incorporate substs flags. + let flags = match self { + LazyConst::Unevaluated(..) => { + TypeFlags::HAS_NORMALIZABLE_PROJECTION | TypeFlags::HAS_PROJECTION + } + LazyConst::Evaluated(c) => { + c.type_flags() + } + }; + + debug!("type_flags({:?}) = {:?}", self, flags); + + flags + } } /// Typed constant value. @@ -2225,6 +2241,33 @@ impl<'tcx> Const<'tcx> { self.assert_usize(tcx).unwrap_or_else(|| bug!("expected constant usize, got {:#?}", self)) } + + pub fn type_flags(&self) -> TypeFlags { + let mut flags = self.ty.flags; + + match self.val { + ConstValue::Param(_) => { + flags |= TypeFlags::HAS_FREE_LOCAL_NAMES; + flags |= TypeFlags::HAS_PARAMS; + } + ConstValue::Infer(infer) => { + flags |= TypeFlags::HAS_FREE_LOCAL_NAMES; + flags |= TypeFlags::HAS_CT_INFER; + match infer { + InferConst::Fresh(_) | + InferConst::Canonical(_, _) => {} + InferConst::Var(_) => { + flags |= TypeFlags::KEEP_IN_LOCAL_TCX; + } + } + } + _ => {} + } + + debug!("type_flags({:?}) = {:?}", self, flags); + + flags + } } impl<'tcx> serialize::UseSpecializedDecodable for &'tcx LazyConst<'tcx> {} From 2ce19ae3d196043281c7572290ee09f502d8384c Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:11:10 +0000 Subject: [PATCH 06/34] Use non_erasable_generics for codegen Co-Authored-By: Gabriel Smith --- src/librustc_codegen_llvm/callee.rs | 2 +- src/librustc_codegen_ssa/back/symbol_export.rs | 2 +- src/librustc_codegen_ssa/mir/operand.rs | 2 ++ src/librustc_codegen_utils/symbol_names.rs | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 43a5767e5c68d..2d732adcb9138 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -113,7 +113,7 @@ pub fn get_fn( unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - let is_generic = instance.substs.types().next().is_some(); + let is_generic = instance.substs.non_erasable_generics().next().is_some(); if is_generic { // This is a monomorphization. Its expected visibility depends diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index 7da28c19d2412..336f41b784a81 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -263,7 +263,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def: InstanceDef::Item(def_id), substs, }) = mono_item { - if substs.types().next().is_some() { + if substs.non_erasable_generics().next().is_some() { symbols.push((ExportedSymbol::Generic(def_id, substs), SymbolExportLevel::Rust)); } diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 0a6549851f446..55a1eb016e0d0 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -76,6 +76,8 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { } let val = match val.val { + ConstValue::Param(_) => bug!("encountered a ConstValue::Param in codegen"), + ConstValue::Infer(_) => bug!("encountered a ConstValue::Infer in codegen"), ConstValue::Scalar(x) => { let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index f529cf30a62ea..76e74e9e2b464 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -172,7 +172,7 @@ fn get_symbol_hash<'a, 'tcx>( assert!(!substs.needs_subst()); substs.hash_stable(&mut hcx, &mut hasher); - let is_generic = substs.types().next().is_some(); + let is_generic = substs.non_erasable_generics().next().is_some(); let avoid_cross_crate_conflicts = // If this is an instance of a generic function, we also hash in // the ID of the instantiating crate. This avoids symbol conflicts From 691d054e05e37ab000a78ddf580ccb8cc96a41e2 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:11:37 +0000 Subject: [PATCH 07/34] Take const generics into account when monomorphising Co-Authored-By: Gabriel Smith --- src/librustc_mir/monomorphize/collector.rs | 28 +++++++--- src/librustc_mir/monomorphize/item.rs | 52 ++++++++++++++----- src/librustc_mir/monomorphize/partitioning.rs | 2 +- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 1f20c70dec503..2ce3bf43cfc77 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -466,7 +466,17 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) { let type_length = instance.substs.types().flat_map(|ty| ty.walk()).count(); - debug!(" => type length={}", type_length); + let const_length = instance.substs.consts() + .filter_map(|ct| { + if let ty::LazyConst::Evaluated(ct) = ct { + Some(ct.ty.walk()) + } else { + None + } + }) + .flatten() + .count(); + debug!(" => type length={}, const length={}", type_length, const_length); // Rust code can easily create exponentially-long types using only a // polynomial recursion depth. Even with the default recursion @@ -475,7 +485,9 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // // Bail out in these cases to avoid that bad user experience. let type_length_limit = *tcx.sess.type_length_limit.get(); - if type_length > type_length_limit { + // We include the const length in the type length, as it's better + // to be overly conservative. + if type_length + const_length > type_length_limit { // The instance name is already known to be too long for rustc. Use // `{:.64}` to avoid blasting the user's terminal with thousands of // lines of type-name. @@ -490,7 +502,7 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diag.note(&format!( "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate", - type_length_limit*2)); + type_length_limit * 2)); diag.emit(); tcx.sess.abort_if_errors(); } @@ -759,10 +771,10 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: return false } - // If this instance has no type parameters, it cannot be a shared + // If this instance has non-erasable parameters, it cannot be a shared // monomorphization. Non-generic instances are already handled above // by `is_reachable_non_generic()` - if substs.types().next().is_none() { + if substs.non_erasable_generics().next().is_none() { return false } @@ -1113,14 +1125,16 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, continue; } - if tcx.generics_of(method.def_id).own_counts().types != 0 { + let counts = tcx.generics_of(method.def_id).own_counts(); + if counts.types + counts.consts != 0 { continue; } let substs = InternalSubsts::for_item(tcx, method.def_id, |param, _| { match param.kind { GenericParamDefKind::Lifetime => tcx.types.re_erased.into(), - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Type { .. } | + GenericParamDefKind::Const => { trait_ref.substs[param.index as usize] } } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 059af2dbba944..f0d19ec8bf2fa 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -1,8 +1,9 @@ use crate::monomorphize::Instance; use rustc::hir; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::mir::interpret::ConstValue; use rustc::session::config::OptLevel; -use rustc::ty::{self, Ty, TyCtxt, ClosureSubsts, GeneratorSubsts}; +use rustc::ty::{self, Ty, TyCtxt, Const, ClosureSubsts, GeneratorSubsts, LazyConst, ParamConst}; use rustc::ty::subst::{SubstsRef, InternalSubsts}; use syntax::ast; use syntax::attr::InlineAttr; @@ -44,7 +45,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { fn is_generic_fn(&self) -> bool { match *self.as_mono_item() { MonoItem::Fn(ref instance) => { - instance.substs.types().next().is_some() + instance.substs.non_erasable_generics().next().is_some() } MonoItem::Static(..) | MonoItem::GlobalAsm(..) => false, @@ -267,7 +268,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { ty::Float(ast::FloatTy::F64) => output.push_str("f64"), ty::Adt(adt_def, substs) => { self.push_def_path(adt_def.did, output); - self.push_type_params(substs, iter::empty(), output, debug); + self.push_generic_params(substs, iter::empty(), output, debug); }, ty::Tuple(component_types) => { output.push('('); @@ -312,7 +313,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { ty::Dynamic(ref trait_data, ..) => { if let Some(principal) = trait_data.principal() { self.push_def_path(principal.def_id(), output); - self.push_type_params( + self.push_generic_params( principal.skip_binder().substs, trait_data.projection_bounds(), output, @@ -373,7 +374,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { self.push_def_path(def_id, output); let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id)); let substs = substs.truncate_to(self.tcx, generics); - self.push_type_params(substs, iter::empty(), output, debug); + self.push_generic_params(substs, iter::empty(), output, debug); } ty::Error | ty::Bound(..) | @@ -394,6 +395,24 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { } } + // FIXME(const_generics): handle debug printing. + pub fn push_const_name(&self, c: &LazyConst<'tcx>, output: &mut String, debug: bool) { + match c { + LazyConst::Unevaluated(..) => output.push_str("_: _"), + LazyConst::Evaluated(Const { ty, val }) => { + match val { + ConstValue::Infer(..) => output.push_str("_"), + ConstValue::Param(ParamConst { name, .. }) => { + write!(output, "{}", name).unwrap(); + } + _ => write!(output, "{:?}", c).unwrap(), + } + output.push_str(": "); + self.push_type_name(ty, output, debug); + } + } + } + pub fn push_def_path(&self, def_id: DefId, output: &mut String) { @@ -421,15 +440,15 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.pop(); } - fn push_type_params(&self, - substs: SubstsRef<'tcx>, - projections: I, - output: &mut String, - debug: bool) - where I: Iterator> - { + fn push_generic_params( + &self, + substs: SubstsRef<'tcx>, + projections: I, + output: &mut String, + debug: bool, + ) where I: Iterator> { let mut projections = projections.peekable(); - if substs.types().next().is_none() && projections.peek().is_none() { + if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() { return; } @@ -449,6 +468,11 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.push_str(", "); } + for const_parameter in substs.consts() { + self.push_const_name(const_parameter, output, debug); + output.push_str(", "); + } + output.pop(); output.pop(); @@ -460,6 +484,6 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output: &mut String, debug: bool) { self.push_def_path(instance.def_id(), output); - self.push_type_params(instance.substs, iter::empty(), output, debug); + self.push_generic_params(instance.substs, iter::empty(), output, debug); } } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index f342017603ed6..f98bc476aafec 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -448,7 +448,7 @@ fn mono_item_visibility( return Visibility::Hidden } - let is_generic = instance.substs.types().next().is_some(); + let is_generic = instance.substs.non_erasable_generics().next().is_some(); // Upstream `DefId` instances get different handling than local ones if !def_id.is_local() { From 1ebc858e5dd01417a05b08bac067bff2c55faca7 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:12:15 +0000 Subject: [PATCH 08/34] Add const kind and UnpackedKind::Const Co-Authored-By: Gabriel Smith --- src/librustc/ty/subst.rs | 116 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 6 deletions(-) diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 450fab81661fc..35c6f980cd934 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -2,8 +2,9 @@ use crate::hir::def_id::DefId; use crate::infer::canonical::Canonical; -use crate::ty::{self, Lift, List, Ty, TyCtxt}; +use crate::ty::{self, Lift, List, Ty, TyCtxt, InferConst, ParamConst}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use crate::mir::interpret::ConstValue; use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; @@ -17,24 +18,26 @@ use std::mem; use std::num::NonZeroUsize; /// An entity in the Rust type system, which can be one of -/// several kinds (only types and lifetimes for now). +/// several kinds (types, lifetimes, and consts). /// To reduce memory usage, a `Kind` is a interned pointer, /// with the lowest 2 bits being reserved for a tag to -/// indicate the type (`Ty` or `Region`) it points to. +/// indicate the type (`Ty`, `Region`, or `Const`) it points to. #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct Kind<'tcx> { ptr: NonZeroUsize, - marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)> + marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, &'tcx ty::LazyConst<'tcx>)> } const TAG_MASK: usize = 0b11; const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; +const CONST_TAG: usize = 0b10; #[derive(Debug, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord)] pub enum UnpackedKind<'tcx> { Lifetime(ty::Region<'tcx>), Type(Ty<'tcx>), + Const(&'tcx ty::LazyConst<'tcx>), } impl<'tcx> UnpackedKind<'tcx> { @@ -50,6 +53,11 @@ impl<'tcx> UnpackedKind<'tcx> { assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0); (TYPE_TAG, ty as *const _ as usize) } + UnpackedKind::Const(ct) => { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(ct) & TAG_MASK, 0); + (CONST_TAG, ct as *const _ as usize) + } }; Kind { @@ -85,6 +93,12 @@ impl<'tcx> From> for Kind<'tcx> { } } +impl<'tcx> From<&'tcx ty::LazyConst<'tcx>> for Kind<'tcx> { + fn from(c: &'tcx ty::LazyConst<'tcx>) -> Kind<'tcx> { + UnpackedKind::Const(c).pack() + } +} + impl<'tcx> Kind<'tcx> { #[inline] pub fn unpack(self) -> UnpackedKind<'tcx> { @@ -93,6 +107,7 @@ impl<'tcx> Kind<'tcx> { match ptr & TAG_MASK { REGION_TAG => UnpackedKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)), TYPE_TAG => UnpackedKind::Type(&*((ptr & !TAG_MASK) as *const _)), + CONST_TAG => UnpackedKind::Const(&*((ptr & !TAG_MASK) as *const _)), _ => intrinsics::unreachable() } } @@ -104,6 +119,7 @@ impl<'tcx> fmt::Debug for Kind<'tcx> { match self.unpack() { UnpackedKind::Lifetime(lt) => write!(f, "{:?}", lt), UnpackedKind::Type(ty) => write!(f, "{:?}", ty), + UnpackedKind::Const(ct) => write!(f, "{:?}", ct), } } } @@ -113,6 +129,7 @@ impl<'tcx> fmt::Display for Kind<'tcx> { match self.unpack() { UnpackedKind::Lifetime(lt) => write!(f, "{}", lt), UnpackedKind::Type(ty) => write!(f, "{}", ty), + UnpackedKind::Const(ct) => write!(f, "{}", ct), } } } @@ -122,8 +139,9 @@ impl<'a, 'tcx> Lift<'tcx> for Kind<'a> { fn lift_to_tcx<'cx, 'gcx>(&self, tcx: TyCtxt<'cx, 'gcx, 'tcx>) -> Option { match self.unpack() { - UnpackedKind::Lifetime(a) => a.lift_to_tcx(tcx).map(|a| a.into()), - UnpackedKind::Type(a) => a.lift_to_tcx(tcx).map(|a| a.into()), + UnpackedKind::Lifetime(lt) => lt.lift_to_tcx(tcx).map(|lt| lt.into()), + UnpackedKind::Type(ty) => ty.lift_to_tcx(tcx).map(|ty| ty.into()), + UnpackedKind::Const(ct) => ct.lift_to_tcx(tcx).map(|ct| ct.into()), } } } @@ -133,6 +151,7 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> { match self.unpack() { UnpackedKind::Lifetime(lt) => lt.fold_with(folder).into(), UnpackedKind::Type(ty) => ty.fold_with(folder).into(), + UnpackedKind::Const(ct) => ct.fold_with(folder).into(), } } @@ -140,6 +159,7 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> { match self.unpack() { UnpackedKind::Lifetime(lt) => lt.visit_with(visitor), UnpackedKind::Type(ty) => ty.visit_with(visitor), + UnpackedKind::Const(ct) => ct.visit_with(visitor), } } } @@ -195,6 +215,15 @@ impl<'a, 'gcx, 'tcx> InternalSubsts<'tcx> { ty::BoundRegion::BrNamed(param.def_id, param.name) )).into() } + + ty::GenericParamDefKind::Const => { + tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer( + InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from(param.index)) + ), + ty: tcx.type_of(def_id), + })).into() + } } }) } @@ -283,6 +312,29 @@ impl<'a, 'gcx, 'tcx> InternalSubsts<'tcx> { }) } + #[inline] + pub fn consts(&'a self) -> impl DoubleEndedIterator> + 'a { + self.iter().filter_map(|k| { + if let UnpackedKind::Const(ct) = k.unpack() { + Some(ct) + } else { + None + } + }) + } + + #[inline] + pub fn non_erasable_generics( + &'a self + ) -> impl DoubleEndedIterator> + 'a { + self.iter().filter_map(|k| { + match k.unpack() { + UnpackedKind::Lifetime(_) => None, + generic => Some(generic), + } + }) + } + #[inline] pub fn type_at(&self, i: usize) -> Ty<'tcx> { if let UnpackedKind::Type(ty) = self[i].unpack() { @@ -301,6 +353,15 @@ impl<'a, 'gcx, 'tcx> InternalSubsts<'tcx> { } } + #[inline] + pub fn const_at(&self, i: usize) -> &'tcx ty::LazyConst<'tcx> { + if let UnpackedKind::Const(ct) = self[i].unpack() { + ct + } else { + bug!("expected const for param #{} in {:?}", i, self); + } + } + #[inline] pub fn type_for_def(&self, def: &ty::GenericParamDef) -> Kind<'tcx> { self.type_at(def.index as usize).into() @@ -469,6 +530,21 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { return t1; } + + fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + if !c.needs_subst() { + return c; + } + + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Param(p), + .. + }) = c { + self.const_for_param(*p, c) + } else { + c.super_fold_with(self) + } + } } impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { @@ -494,6 +570,34 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { self.shift_vars_through_binders(ty) } + fn const_for_param( + &self, + p: ParamConst, + source_cn: &'tcx ty::LazyConst<'tcx> + ) -> &'tcx ty::LazyConst<'tcx> { + // Look up the const in the substitutions. It really should be in there. + let opt_cn = self.substs.get(p.index as usize).map(|k| k.unpack()); + let cn = match opt_cn { + Some(UnpackedKind::Const(cn)) => cn, + _ => { + let span = self.span.unwrap_or(DUMMY_SP); + span_bug!( + span, + "Const parameter `{:?}` ({:?}/{}) out of range \ + when substituting (root type={:?}) substs={:?}", + p, + source_cn, + p.index, + self.root_ty, + self.substs, + ); + } + }; + + // FIXME(const_generics): shift const through binders + cn + } + /// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs /// when we are substituting a type with escaping bound vars into a context where we have /// passed through binders. That's quite a mouthful. Let's see an example: From 7f2a4f78224f9442bca6ceb7739d3d86a7591153 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:12:46 +0000 Subject: [PATCH 09/34] Add ConstValue::Param and ConstValue::Infer Co-Authored-By: Gabriel Smith --- src/librustc/mir/interpret/value.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 956182fc8b275..dbbeda3e578e4 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -1,6 +1,6 @@ use std::fmt; -use crate::ty::{Ty, layout::{HasDataLayout, Size}}; +use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}}; use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate}; @@ -17,6 +17,12 @@ pub struct RawConst<'tcx> { /// match the `LocalState` optimizations for easy conversions between `Value` and `ConstValue`. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)] pub enum ConstValue<'tcx> { + /// A const generic parameter. + Param(ParamConst), + + /// Infer the value of the const. + Infer(InferConst<'tcx>), + /// Used only for types with `layout::abi::Scalar` ABI and ZSTs. /// /// Not using the enum `Value` to encode that this must not be `Undef`. @@ -43,6 +49,8 @@ impl<'tcx> ConstValue<'tcx> { #[inline] pub fn try_to_scalar(&self) -> Option { match *self { + ConstValue::Param(_) | + ConstValue::Infer(_) | ConstValue::ByRef(..) | ConstValue::Slice(..) => None, ConstValue::Scalar(val) => Some(val), From f7f60eef500cbba168bec1034a087a6feb625982 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:13:19 +0000 Subject: [PATCH 10/34] Add type constraints from const parameters Co-Authored-By: Gabriel Smith --- src/librustc_typeck/variance/constraints.rs | 49 ++++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index d8d93b462a900..49d11150689a9 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -4,7 +4,8 @@ //! We walk the set of items and, for each member, generate new constraints. use hir::def_id::DefId; -use rustc::ty::subst::{UnpackedKind, SubstsRef}; +use rustc::mir::interpret::ConstValue; +use rustc::ty::subst::{SubstsRef, UnpackedKind}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -229,12 +230,19 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // 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); + for k in substs { + match k.unpack() { + UnpackedKind::Lifetime(lt) => { + self.add_constraints_from_region(current, lt, variance_i) + } + UnpackedKind::Type(ty) => { + self.add_constraints_from_ty(current, ty, variance_i) + } + UnpackedKind::Const(ct) => { + self.add_constraints_from_const(current, ct, variance_i) + } + } } } @@ -267,7 +275,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance); } - ty::Array(typ, _) | + ty::Array(typ, len) => { + self.add_constraints_from_ty(current, typ, variance); + self.add_constraints_from_const(current, len, variance); + } + ty::Slice(typ) => { self.add_constraints_from_ty(current, typ, variance); } @@ -383,6 +395,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { UnpackedKind::Type(ty) => { self.add_constraints_from_ty(current, ty, variance_i) } + UnpackedKind::Const(ct) => { + self.add_constraints_from_const(current, ct, variance_i) + } } } } @@ -434,6 +449,26 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } + fn add_constraints_from_const( + &mut self, + current: &CurrentItem, + ct: &ty::LazyConst<'tcx>, + variance: VarianceTermPtr<'a> + ) { + debug!( + "add_constraints_from_const(ct={:?}, variance={:?})", + ct, + variance + ); + + if let ty::LazyConst::Evaluated(ct) = ct { + self.add_constraints_from_ty(current, ct.ty, variance); + if let ConstValue::Param(ref data) = ct.val { + self.add_constraint(current, data.index, variance); + } + } + } + /// Adds constraints appropriate for a mutability-type pair /// appearing in a context with ambient variance `variance` fn add_constraints_from_mt(&mut self, From 73a6df6079c052f789ef8d5e0aaaf855ffbc76f4 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:13:32 +0000 Subject: [PATCH 11/34] Update diagnostics to include const parameters Co-Authored-By: Gabriel Smith --- src/librustc_typeck/diagnostics.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index feff79dc3f508..399cd6f890c25 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -423,7 +423,7 @@ impl Foo for Bar { E0049: r##" This error indicates that an attempted implementation of a trait method -has the wrong number of type parameters. +has the wrong number of type or const parameters. For example, the trait below has a method `foo` with a type parameter `T`, but the implementation of `foo` for the type `Bar` is missing this parameter: @@ -1032,6 +1032,7 @@ enum NightsWatch {} ``` "##, +// FIXME(const_generics:docs): example of inferring const parameter. E0087: r##" #### Note: this error code is no longer emitted by the compiler. @@ -1152,8 +1153,8 @@ fn main() { "##, E0091: r##" -You gave an unnecessary type parameter in a type alias. Erroneous code -example: +You gave an unnecessary type or const parameter in a type alias. Erroneous +code example: ```compile_fail,E0091 type Foo = u32; // error: type parameter `T` is unused @@ -1161,7 +1162,7 @@ type Foo = u32; // error: type parameter `T` is unused type Foo = Box; // error: type parameter `B` is unused ``` -Please check you didn't write too many type parameters. Example: +Please check you didn't write too many parameters. Example: ``` type Foo = u32; // ok! From 9a9aa5b46aa0c81a6dad3a3377d6b7d2e65a93c7 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:13:49 +0000 Subject: [PATCH 12/34] Implement Hash for new types Co-Authored-By: Gabriel Smith --- src/librustc/ich/impls_ty.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f77a88128f252..21988de90183a 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -74,6 +74,7 @@ for ty::subst::UnpackedKind<'gcx> { match self { ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher), ty::subst::UnpackedKind::Type(ty) => ty.hash_stable(hcx, hasher), + ty::subst::UnpackedKind::Const(ct) => ct.hash_stable(hcx, hasher), } } } @@ -134,6 +135,15 @@ impl<'a> HashStable> for ty::RegionVid { } } +impl<'gcx, 'tcx> HashStable> for ty::ConstVid<'tcx> { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + self.index.hash_stable(hcx, hasher); + } +} + impl<'gcx> HashStable> for ty::BoundVar { #[inline] fn hash_stable(&self, @@ -297,6 +307,14 @@ impl<'a> HashStable> for ty::VariantFlags { } } +impl_stable_hash_for!( + impl<'tcx> for enum ty::InferConst<'tcx> [ ty::InferConst ] { + Var(vid), + Fresh(i), + Canonical(debruijn, var), + } +); + impl_stable_hash_for!(enum ty::VariantDiscr { Explicit(def_id), Relative(distance) @@ -310,11 +328,14 @@ impl_stable_hash_for!(struct ty::FieldDef { impl_stable_hash_for!( impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] { + Param(param), + Infer(infer), Scalar(val), Slice(a, b), ByRef(ptr, alloc), } ); + impl_stable_hash_for!(struct crate::mir::interpret::RawConst<'tcx> { alloc_id, ty, @@ -518,6 +539,7 @@ impl_stable_hash_for!(struct ty::GenericParamDef { impl_stable_hash_for!(enum ty::GenericParamDefKind { Lifetime, Type { has_default, object_lifetime_default, synthetic }, + Const, }); impl_stable_hash_for!( @@ -736,6 +758,11 @@ for ty::FloatVid } } +impl_stable_hash_for!(struct ty::ParamConst { + index, + name +}); + impl_stable_hash_for!(struct ty::ParamTy { idx, name From 63b7572d0df999ce6d2a9e62878b36e44a81df05 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:14:18 +0000 Subject: [PATCH 13/34] Stub methods in infer Co-Authored-By: Gabriel Smith --- src/librustc/infer/canonical/mod.rs | 3 +++ src/librustc/infer/canonical/query_response.rs | 15 +++++++++++++++ src/librustc/infer/combine.rs | 2 +- src/librustc/infer/error_reporting/mod.rs | 16 +++++----------- src/librustc/infer/mod.rs | 13 ++++++++----- src/librustc/infer/nll_relate/mod.rs | 4 ++-- 6 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 613e153ae33d4..0d067d1de856a 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -443,6 +443,9 @@ impl<'tcx> CanonicalVarValues<'tcx> { UnpackedKind::Lifetime(..) => tcx.mk_region( ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i)) ).into(), + UnpackedKind::Const(..) => { + unimplemented!() // FIXME(const_generics) + } }) .collect() } diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index aef0152b6ed73..008882fd50036 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -315,6 +315,10 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { obligations.extend(ok.into_obligations()); } + (UnpackedKind::Const(..), UnpackedKind::Const(..)) => { + unimplemented!() // FIXME(const_generics) + } + _ => { bug!( "kind mismatch, cannot unify {:?} and {:?}", @@ -473,6 +477,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { opt_values[br.assert_bound_var()] = Some(*original_value); } } + UnpackedKind::Const(..) => { + unimplemented!() // FIXME(const_generics) + } } } @@ -568,6 +575,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { ty::OutlivesPredicate(t1, r2) ) ), + UnpackedKind::Const(..) => { + // Consts cannot outlive one another, so we don't expect to + // ecounter this branch. + span_bug!(cause.span, "unexpected const outlives {:?}", constraint); + } } ) }) @@ -602,6 +614,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { obligations .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); } + (UnpackedKind::Const(..), UnpackedKind::Const(..)) => { + unimplemented!() // FIXME(const_generics) + } _ => { bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); } diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 6ef902a47dc8d..885b439ef1ca5 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -449,7 +449,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' let origin = *variables.var_origin(vid); let new_var_id = variables.new_var(self.for_universe, false, origin); - let u = self.tcx().mk_var(new_var_id); + let u = self.tcx().mk_ty_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); return Ok(u); diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 3dace2f2e89b0..c7936534aad2e 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -691,17 +691,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ) -> SubstsRef<'tcx> { let generics = self.tcx.generics_of(def_id); let mut num_supplied_defaults = 0; - let mut type_params = generics - .params - .iter() - .rev() - .filter_map(|param| match param.kind { - ty::GenericParamDefKind::Lifetime => None, - ty::GenericParamDefKind::Type { has_default, .. } => { - Some((param.def_id, has_default)) - } - }) - .peekable(); + let mut type_params = generics.params.iter().rev().filter_map(|param| match param.kind { + ty::GenericParamDefKind::Lifetime => None, + ty::GenericParamDefKind::Type { has_default, .. } => Some((param.def_id, has_default)), + ty::GenericParamDefKind::Const => None, // FIXME(const_generics:defaults) + }).peekable(); let has_default = { let has_default = type_params.peek().map(|(_, has_default)| has_default); *has_default.unwrap_or(&false) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 84ad742d3c972..cc1c439f3bd94 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -656,7 +656,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { type_variables .unsolved_variables() .into_iter() - .map(|t| self.tcx.mk_var(t)) + .map(|t| self.tcx.mk_ty_var(t)) .chain( (0..int_unification_table.len()) .map(|i| ty::IntVid { index: i as u32 }) @@ -981,7 +981,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_var(self.next_ty_var_id(false, origin)) + self.tcx.mk_ty_var(self.next_ty_var_id(false, origin)) } pub fn next_ty_var_in_universe( @@ -992,11 +992,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let vid = self.type_variables .borrow_mut() .new_var(universe, false, origin); - self.tcx.mk_var(vid) + self.tcx.mk_ty_var(vid) } pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_var(self.next_ty_var_id(true, origin)) + self.tcx.mk_ty_var(self.next_ty_var_id(true, origin)) } pub fn next_int_var_id(&self) -> IntVid { @@ -1081,7 +1081,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { TypeVariableOrigin::TypeParameterDefinition(span, param.name), ); - self.tcx.mk_var(ty_var_id).into() + self.tcx.mk_ty_var(ty_var_id).into() + } + GenericParamDefKind::Const { .. } => { + unimplemented!() // FIXME(const_generics) } } } diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index f37e24b292e03..7140af36acbdc 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -310,7 +310,7 @@ where ty::Projection(projection_ty) if D::normalization() == NormalizationStrategy::Lazy => { - return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_var(vid))); + return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_ty_var(vid))); } _ => (), @@ -764,7 +764,7 @@ where // the universe `_universe`. let new_var_id = variables.new_var(self.universe, false, origin); - let u = self.tcx().mk_var(new_var_id); + let u = self.tcx().mk_ty_var(new_var_id); debug!( "generalize: replacing original vid={:?} with new={:?}", vid, From 29c272d4edcd1974c2c501a9310acbb30c65fe54 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:14:56 +0000 Subject: [PATCH 14/34] Take const into account in context Co-Authored-By: Gabriel Smith --- src/librustc/ty/context.rs | 100 +++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 26 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3c63dcb9ef307..f6e6067bb6fc8 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -21,8 +21,8 @@ use crate::middle::lang_items; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use crate::middle::stability; use crate::mir::{self, Mir, interpret, ProjectionKind}; -use crate::mir::interpret::Allocation; -use crate::ty::subst::{Kind, InternalSubsts, Subst, SubstsRef}; +use crate::mir::interpret::{ConstValue, Allocation}; +use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst}; use crate::ty::ReprOptions; use crate::traits; use crate::traits::{Clause, Clauses, GoalKind, Goal, Goals}; @@ -31,8 +31,9 @@ use crate::ty::{TyS, TyKind, List}; use crate::ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const, LazyConst}; use crate::ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate}; use crate::ty::RegionKind; -use crate::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; +use crate::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid, ConstVid}; use crate::ty::TyKind::*; +use crate::ty::{InferConst, ParamConst}; use crate::ty::GenericParamDefKind; use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx}; use crate::ty::query; @@ -872,6 +873,18 @@ impl CanonicalUserType<'gcx> { } _ => false, }, + + UnpackedKind::Const(ct) => match ct { + ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Canonical(debruijn, b)), + .. + }) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(*debruijn, ty::INNERMOST); + cvar == *b + } + _ => false, + }, } }) }, @@ -2120,15 +2133,19 @@ macro_rules! sty_debug_print { #[derive(Copy, Clone)] struct DebugStat { total: usize, - region_infer: usize, + lt_infer: usize, ty_infer: usize, - both_infer: usize, + ct_infer: usize, + all_infer: usize, } pub fn go(tcx: TyCtxt<'_, '_, '_>) { let mut total = DebugStat { total: 0, - region_infer: 0, ty_infer: 0, both_infer: 0, + lt_infer: 0, + ty_infer: 0, + ct_infer: 0, + all_infer: 0, }; $(let mut $variant = total;)* @@ -2139,31 +2156,35 @@ macro_rules! sty_debug_print { ty::Error => /* unimportant */ continue, $(ty::$variant(..) => &mut $variant,)* }; - let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER); + let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER); let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER); + let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER); variant.total += 1; total.total += 1; - if region { total.region_infer += 1; variant.region_infer += 1 } + if lt { total.lt_infer += 1; variant.lt_infer += 1 } if ty { total.ty_infer += 1; variant.ty_infer += 1 } - if region && ty { total.both_infer += 1; variant.both_infer += 1 } + if ct { total.ct_infer += 1; variant.ct_infer += 1 } + if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 } } - println!("Ty interner total ty region both"); + println!("Ty interner total ty lt ct all"); $(println!(" {:18}: {uses:6} {usespc:4.1}%, \ - {ty:4.1}% {region:5.1}% {both:4.1}%", - stringify!($variant), - uses = $variant.total, - usespc = $variant.total as f64 * 100.0 / total.total as f64, - ty = $variant.ty_infer as f64 * 100.0 / total.total as f64, - region = $variant.region_infer as f64 * 100.0 / total.total as f64, - both = $variant.both_infer as f64 * 100.0 / total.total as f64); - )* + {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%", + stringify!($variant), + uses = $variant.total, + usespc = $variant.total as f64 * 100.0 / total.total as f64, + ty = $variant.ty_infer as f64 * 100.0 / total.total as f64, + lt = $variant.lt_infer as f64 * 100.0 / total.total as f64, + ct = $variant.ct_infer as f64 * 100.0 / total.total as f64, + all = $variant.all_infer as f64 * 100.0 / total.total as f64); + )* println!(" total {uses:6} \ - {ty:4.1}% {region:5.1}% {both:4.1}%", - uses = total.total, - ty = total.ty_infer as f64 * 100.0 / total.total as f64, - region = total.region_infer as f64 * 100.0 / total.total as f64, - both = total.both_infer as f64 * 100.0 / total.total as f64) + {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%", + uses = total.total, + ty = total.ty_infer as f64 * 100.0 / total.total as f64, + lt = total.lt_infer as f64 * 100.0 / total.total as f64, + ct = total.ct_infer as f64 * 100.0 / total.total as f64, + all = total.all_infer as f64 * 100.0 / total.total as f64) } } @@ -2518,7 +2539,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let adt_def = self.adt_def(def_id); let substs = InternalSubsts::for_item(self, def_id, |param, substs| { match param.kind { - GenericParamDefKind::Lifetime => bug!(), + GenericParamDefKind::Lifetime | + GenericParamDefKind::Const => { + bug!() + } GenericParamDefKind::Type { has_default, .. } => { if param.index == 0 { ty.into() @@ -2659,10 +2683,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } #[inline] - pub fn mk_var(self, v: TyVid) -> Ty<'tcx> { + pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> { self.mk_infer(TyVar(v)) } + #[inline] + pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> &'tcx LazyConst<'tcx> { + self.mk_lazy_const(LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Var(v)), + ty, + })) + } + #[inline] pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> { self.mk_infer(IntVar(v)) @@ -2685,6 +2717,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(Param(ParamTy { idx: index, name: name })) } + #[inline] + pub fn mk_const_param( + self, + index: u32, + name: InternedString, + ty: Ty<'tcx> + ) -> &'tcx LazyConst<'tcx> { + self.mk_lazy_const(LazyConst::Evaluated(ty::Const { + val: ConstValue::Param(ParamConst { index, name }), + ty, + })) + } + #[inline] pub fn mk_self_type(self) -> Ty<'tcx> { self.mk_ty_param(0, keywords::SelfUpper.name().as_interned_str()) @@ -2695,7 +2740,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { GenericParamDefKind::Lifetime => { self.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())).into() } - GenericParamDefKind::Type {..} => self.mk_ty_param(param.index, param.name).into(), + GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(), + GenericParamDefKind::Const => { + self.mk_const_param(param.index, param.name, self.type_of(param.def_id)).into() + } } } From cbf5d22bcdd8674db1f3945326e4ff8d6b6986c8 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:15:21 +0000 Subject: [PATCH 15/34] Add const type flags Co-Authored-By: Gabriel Smith --- src/librustc/ty/flags.rs | 32 ++++++++++++++++++++++++-------- src/librustc/ty/fold.rs | 19 ++++++++++--------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 2b12dcca93ad7..64ceb9729ed15 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -1,5 +1,6 @@ -use crate::ty::subst::SubstsRef; -use crate::ty::{self, Ty, TypeFlags, TypeFoldable}; +use crate::ty::subst::{SubstsRef, UnpackedKind}; +use crate::ty::{self, Ty, TypeFlags, TypeFoldable, InferConst}; +use crate::mir::interpret::ConstValue; #[derive(Debug)] pub struct FlagComputation { @@ -232,6 +233,21 @@ impl FlagComputation { } } + fn add_const(&mut self, c: &ty::LazyConst<'_>) { + match c { + ty::LazyConst::Unevaluated(_, substs) => self.add_substs(substs), + // Only done to add the binder for the type. The type flags are + // included in `Const::type_flags`. + ty::LazyConst::Evaluated(ty::Const { ty, val }) => { + self.add_ty(ty); + if let ConstValue::Infer(InferConst::Canonical(debruijn, _)) = val { + self.add_binder(*debruijn) + } + } + } + self.add_flags(c.type_flags()); + } + fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) { self.add_substs(projection.substs); self.add_ty(projection.ty); @@ -242,12 +258,12 @@ impl FlagComputation { } fn add_substs(&mut self, substs: SubstsRef<'_>) { - for ty in substs.types() { - self.add_ty(ty); - } - - for r in substs.regions() { - self.add_region(r); + for kind in substs { + match kind.unpack() { + UnpackedKind::Type(ty) => self.add_ty(ty), + UnpackedKind::Lifetime(lt) => self.add_region(lt), + UnpackedKind::Const(ct) => self.add_const(ct), + } } } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index aa4d1e5ea90cb..7f77d037bb6a1 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -91,7 +91,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.has_type_flags(TypeFlags::HAS_TY_INFER) } fn needs_infer(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) + self.has_type_flags( + TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER | TypeFlags::HAS_CT_INFER + ) } fn has_placeholders(&self) -> bool { self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER) @@ -117,7 +119,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } /// Indicates whether this value references only 'global' - /// types/lifetimes that are the same regardless of what fn we are + /// generic parameters that are the same regardless of what fn we are /// in. This is used for caching. fn is_global(&self) -> bool { !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) @@ -841,14 +843,13 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool { - if let ty::LazyConst::Unevaluated(..) = c { - let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION | - TypeFlags::HAS_PROJECTION; - if projection_flags.intersects(self.flags) { - return true; - } + let flags = c.type_flags(); + debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); + if flags.intersects(self.flags) { + true + } else { + c.super_visit_with(self) } - c.super_visit_with(self) } } From 0d1c9c08d7afd83644c825305804eb694bddb881 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:15:49 +0000 Subject: [PATCH 16/34] Pretty printing for const generics Co-Authored-By: Gabriel Smith --- src/librustc/util/ppaux.rs | 70 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index aecef3c5ec71e..cdc0c3371ebcd 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -8,7 +8,8 @@ use crate::ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr}; use crate::ty::{Param, Bound, RawPtr, Ref, Never, Tuple}; use crate::ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque}; use crate::ty::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind, ParamConst}; +use crate::mir::interpret::ConstValue; use crate::util::nodemap::FxHashSet; use std::cell::Cell; @@ -478,6 +479,7 @@ impl PrintContext { GenericParamDefKind::Type { has_default, .. } => { Some((param.def_id, has_default)) } + GenericParamDefKind::Const => None, // FIXME(const_generics:defaults) }).peekable(); let has_default = { let has_default = type_params.peek().map(|(_, has_default)| has_default); @@ -571,6 +573,14 @@ impl PrintContext { )?; } + // FIXME(const_generics::defaults) + let consts = substs.consts(); + + for ct in consts { + start_or_continue(f, "<", ", ")?; + ct.print_display(f, self)?; + } + start_or_continue(f, "", ">")?; // For values, also print their name and type parameters. @@ -763,7 +773,8 @@ impl fmt::Debug for ty::GenericParamDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let type_name = match self.kind { ty::GenericParamDefKind::Lifetime => "Lifetime", - ty::GenericParamDefKind::Type {..} => "Type", + ty::GenericParamDefKind::Type { .. } => "Type", + ty::GenericParamDefKind::Const => "Const", }; write!(f, "{}({}, {:?}, {})", type_name, @@ -1088,6 +1099,12 @@ impl fmt::Debug for ty::TyVid { } } +impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "_#{}f", self.index) + } +} + impl fmt::Debug for ty::IntVid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "_#{}i", self.index) @@ -1448,7 +1465,12 @@ define_print! { write!(f, "_")?; } ty::LazyConst::Evaluated(c) => ty::tls::with(|tcx| { - write!(f, "{}", c.unwrap_usize(tcx)) + match c.val { + ConstValue::Infer(..) => write!(f, "_"), + ConstValue::Param(ParamConst { name, .. }) => + write!(f, "{}", name), + _ => write!(f, "{}", c.unwrap_usize(tcx)), + } })?, } write!(f, "]") @@ -1472,6 +1494,37 @@ define_print! { } } +define_print! { + ('tcx) ConstValue<'tcx>, (self, f, cx) { + display { + match self { + ConstValue::Infer(..) => write!(f, "_"), + ConstValue::Param(ParamConst { name, .. }) => write!(f, "{}", name), + _ => write!(f, "{:?}", self), + } + } + } +} + +define_print! { + ('tcx) ty::Const<'tcx>, (self, f, cx) { + display { + write!(f, "{} : {}", self.val, self.ty) + } + } +} + +define_print! { + ('tcx) ty::LazyConst<'tcx>, (self, f, cx) { + display { + match self { + ty::LazyConst::Unevaluated(..) => write!(f, "_ : _"), + ty::LazyConst::Evaluated(c) => write!(f, "{}", c), + } + } + } +} + define_print! { () ty::ParamTy, (self, f, cx) { display { @@ -1483,6 +1536,17 @@ define_print! { } } +define_print! { + () ty::ParamConst, (self, f, cx) { + display { + write!(f, "{}", self.name) + } + debug { + write!(f, "{}/#{}", self.name, self.index) + } + } +} + define_print! { ('tcx, T: Print + fmt::Debug, U: Print + fmt::Debug) ty::OutlivesPredicate, (self, f, cx) { From f761c414b12f3851ddef7b5849bb8fdcf8d75d44 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:16:12 +0000 Subject: [PATCH 17/34] Make a lazy const from a const param Co-Authored-By: Gabriel Smith --- src/librustc_mir/hair/cx/expr.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 65cd9f7103d68..e70756ad2f251 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -5,7 +5,7 @@ use crate::hair::cx::to_ref::ToRef; use crate::hair::util::UserAnnotatedTyHelpers; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def::{Def, CtorKind}; -use rustc::mir::interpret::{GlobalId, ErrorHandled}; +use rustc::mir::interpret::{GlobalId, ErrorHandled, ConstValue}; use rustc::ty::{self, AdtKind, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; use rustc::ty::cast::CastKind as TyCastKind; @@ -699,7 +699,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; let source = if let Some((did, offset, var_ty)) = var { - let mk_const = |literal| Expr { + let mk_lazy_const = |literal| Expr { temp_lifetime, ty: var_ty, span: expr.span, @@ -708,7 +708,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, user_ty: None }, }.to_ref(); - let offset = mk_const(ty::LazyConst::Evaluated(ty::Const::from_bits( + let offset = mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bits( cx.tcx, offset as u128, cx.param_env.and(var_ty), @@ -718,7 +718,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = InternalSubsts::identity_for_item(cx.tcx(), did); - let lhs = mk_const(ty::LazyConst::Unevaluated(did, substs)); + let lhs = mk_lazy_const(ty::LazyConst::Unevaluated(did, substs)); let bin = ExprKind::Binary { op: BinOp::Add, lhs, @@ -925,7 +925,26 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ))), user_ty, } - }, + } + + Def::ConstParam(def_id) => { + let node_id = cx.tcx.hir().as_local_node_id(def_id).unwrap(); + let item_id = cx.tcx.hir().get_parent_node(node_id); + let item_def_id = cx.tcx.hir().local_def_id(item_id); + let generics = cx.tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&cx.tcx.hir().local_def_id(node_id)]; + let name = cx.tcx.hir().name(node_id).as_interned_str(); + let val = ConstValue::Param(ty::ParamConst::new(index, name)); + ExprKind::Literal { + literal: cx.tcx.mk_lazy_const( + ty::LazyConst::Evaluated(ty::Const { + val, + ty: cx.tables().node_type(expr.hir_id), + }) + ), + user_ty: None, + } + } Def::Const(def_id) | Def::AssociatedConst(def_id) => { From f7cd97f7863fb9ee017aacec134589c211786c88 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:16:42 +0000 Subject: [PATCH 18/34] Add ast_const_to_const Co-Authored-By: Gabriel Smith --- src/librustc_typeck/astconv.rs | 85 +++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5dbcf908020b0..1dec2d483b80f 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -3,7 +3,7 @@ //! instance of `AstConv`. use errors::{Applicability, DiagnosticId}; -use crate::hir::{self, GenericArg, GenericArgs}; +use crate::hir::{self, GenericArg, GenericArgs, ExprKind}; use crate::hir::def::Def; use crate::hir::def_id::DefId; use crate::hir::HirVec; @@ -16,6 +16,7 @@ use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::{GenericParamDef, GenericParamDefKind}; use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef}; use rustc::ty::wf::object_region_bounds; +use rustc::mir::interpret::ConstValue; use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi; use crate::require_c_abi_if_c_variadic; @@ -273,6 +274,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let param_counts = def.own_counts(); let arg_counts = args.own_counts(); let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; + let infer_consts = position != GenericArgPosition::Type && arg_counts.consts == 0; let mut defaults: ty::GenericParamCount = Default::default(); for param in &def.params { @@ -281,6 +283,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { GenericParamDefKind::Type { has_default, .. } => { defaults.types += has_default as usize } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + } }; } @@ -311,11 +316,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } } - let check_kind_count = |kind, - required, - permitted, - provided, - offset| { + let check_kind_count = |kind, required, permitted, provided, offset| { + debug!( + "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", + kind, + required, + permitted, + provided, + offset + ); // We enforce the following: `required` <= `provided` <= `permitted`. // For kinds without defaults (i.e., lifetimes), `required == permitted`. // For other kinds (i.e., types), `permitted` may be greater than `required`. @@ -384,6 +393,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { 0, ); } + // FIXME(const_generics:defaults) + if !infer_consts || arg_counts.consts > param_counts.consts { + check_kind_count( + "const", + param_counts.consts, + param_counts.consts, + arg_counts.consts, + arg_counts.lifetimes + arg_counts.types, + ); + } + // Note that type errors are currently be emitted *after* const errors. if !infer_types || arg_counts.types > param_counts.types - defaults.types - has_self as usize { check_kind_count( @@ -495,7 +515,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { (Some(&arg), Some(¶m)) => { match (arg, ¶m.kind) { (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime) - | (GenericArg::Type(_), GenericParamDefKind::Type { .. }) => { + | (GenericArg::Type(_), GenericParamDefKind::Type { .. }) + | (GenericArg::Const(_), GenericParamDefKind::Const) => { substs.push(provided_kind(param, arg)); args.next(); params.next(); @@ -606,6 +627,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.ast_ty_to_ty(&ty).into() } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.ast_const_to_const(&ct.value, tcx.type_of(param.def_id)).into() + } _ => unreachable!(), } }, @@ -654,6 +678,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { tcx.types.err.into() } } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + // We've already errored above about the mismatch. + tcx.types.err.into() + } } }, ); @@ -1609,6 +1638,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // Case 3. Reference to a top-level value. Def::Fn(def_id) | Def::Const(def_id) | + Def::ConstParam(def_id) | Def::Static(def_id, _) => { path_segs.push(PathSeg(def_id, last)); } @@ -1797,10 +1827,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, def, segment, false).0 } hir::TyKind::Array(ref ty, ref length) => { - let length_def_id = tcx.hir().local_def_id_from_hir_id(length.hir_id); - let substs = InternalSubsts::identity_for_item(tcx, length_def_id); - let length = ty::LazyConst::Unevaluated(length_def_id, substs); - let length = tcx.mk_lazy_const(length); + let length = self.ast_const_to_const(length, tcx.types.usize); let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); self.normalize_ty(ast_ty.span, array_ty) } @@ -1837,6 +1864,42 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { result_ty } + pub fn ast_const_to_const( + &self, + ast_const: &hir::AnonConst, + ty: Ty<'tcx> + ) -> &'tcx ty::LazyConst<'tcx> { + debug!("ast_const_to_const(id={:?}, ast_const={:?})", ast_const.id, ast_const); + + let tcx = self.tcx(); + let def_id = tcx.hir().local_def_id(ast_const.id); + + let mut lazy_const = ty::LazyConst::Unevaluated( + def_id, + Substs::identity_for_item(tcx, def_id) + ); + + let expr = &tcx.hir().body(ast_const.body).value; + if let ExprKind::Path(ref qpath) = expr.node { + if let hir::QPath::Resolved(_, ref path) = qpath { + if let Def::ConstParam(def_id) = path.def { + let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); + let item_id = tcx.hir().get_parent_node(node_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(node_id)]; + let name = tcx.hir().name(node_id).as_interned_str(); + lazy_const = ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Param(ty::ParamConst::new(index, name)), + ty, + }) + } + } + }; + + tcx.mk_lazy_const(lazy_const) + } + pub fn impl_trait_ty_to_ty( &self, def_id: DefId, From a8361eb6fa42a0cf609d7bbec493702ee2193d7b Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:16:52 +0000 Subject: [PATCH 19/34] Refactor compare_method Co-Authored-By: Gabriel Smith --- src/librustc_typeck/check/compare_method.rs | 113 ++++++++++++-------- 1 file changed, 68 insertions(+), 45 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 59766e7e47d6a..32640d7d9a886 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -6,7 +6,7 @@ use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{Subst, InternalSubsts, SubstsRef}; use rustc::util::common::ErrorReported; -use errors::Applicability; +use errors::{Applicability, DiagnosticId}; use syntax_pos::Span; @@ -576,55 +576,78 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } -fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_m: &ty::AssociatedItem, - impl_m_span: Span, - trait_m: &ty::AssociatedItem, - trait_item_span: Option) - -> Result<(), ErrorReported> { - let impl_m_generics = tcx.generics_of(impl_m.def_id); - let trait_m_generics = tcx.generics_of(trait_m.def_id); - let num_impl_m_type_params = impl_m_generics.own_counts().types; - let num_trait_m_type_params = trait_m_generics.own_counts().types; - - if num_impl_m_type_params != num_trait_m_type_params { - let impl_m_node_id = tcx.hir().as_local_node_id(impl_m.def_id).unwrap(); - let impl_m_item = tcx.hir().expect_impl_item(impl_m_node_id); - let span = if impl_m_item.generics.params.is_empty() - || impl_m_item.generics.span.is_dummy() // impl Trait in argument position (#55374) - { - impl_m_span - } else { - impl_m_item.generics.span - }; +fn compare_number_of_generics<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + impl_: &ty::AssociatedItem, + impl_span: Span, + trait_: &ty::AssociatedItem, + trait_span: Option, +) -> Result<(), ErrorReported> { + let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts(); + let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts(); + + let matchings = [ + ("type", trait_own_counts.types, impl_own_counts.types), + ("const", trait_own_counts.consts, impl_own_counts.consts), + ]; + + let mut err_occurred = false; + for &(kind, trait_count, impl_count) in &matchings { + if impl_count != trait_count { + err_occurred = true; + + let impl_node_id = tcx.hir().as_local_node_id(impl_.def_id).unwrap(); + let impl_item = tcx.hir().expect_impl_item(impl_node_id); + let span = if impl_item.generics.params.is_empty() + || impl_item.generics.span.is_dummy() { // argument position impl Trait (#55374) + impl_span + } else { + impl_item.generics.span + }; - let mut err = struct_span_err!(tcx.sess, span, E0049, - "method `{}` has {} but its trait declaration has {}", - trait_m.ident, - potentially_plural_count(num_impl_m_type_params, "type parameter"), - potentially_plural_count(num_trait_m_type_params, "type parameter") - ); + let mut err = tcx.sess.struct_span_err_with_code( + span, + &format!( + "method `{}` has {} {kind} parameter{} but its trait \ + declaration has {} {kind} parameter{}", + trait_.ident, + impl_count, + if impl_count != 1 { "s" } else { "" }, + trait_count, + if trait_count != 1 { "s" } else { "" }, + kind = kind, + ), + DiagnosticId::Error("E0049".into()), + ); - let mut suffix = None; + let mut suffix = None; - if let Some(span) = trait_item_span { - err.span_label(span, format!("expected {}", - potentially_plural_count(num_trait_m_type_params, "type parameter"))); - } else { - suffix = Some(format!(", expected {}", num_trait_m_type_params)); - } - - err.span_label(span, - format!("found {}{}", - potentially_plural_count(num_impl_m_type_params, "type parameter"), - suffix.as_ref().map(|s| &s[..]).unwrap_or(""))); + if let Some(span) = trait_span { + err.span_label( + span, + format!("expected {} {} parameter{}", trait_count, kind, + if trait_count != 1 { "s" } else { "" }) + ); + } else { + suffix = Some(format!(", expected {}", trait_count)); + } - err.emit(); + err.span_label( + span, + format!("found {} {} parameter{}{}", impl_count, kind, + if impl_count != 1 { "s" } else { "" }, + suffix.unwrap_or_else(|| String::new())), + ); - return Err(ErrorReported); + err.emit(); + } } - Ok(()) + if err_occurred { + Err(ErrorReported) + } else { + Ok(()) + } } fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -725,12 +748,12 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_m_generics = tcx.generics_of(trait_m.def_id); let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind { GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), - GenericParamDefKind::Lifetime => None, + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, }); let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| { match param.kind { GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), - GenericParamDefKind::Lifetime => None, + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, } }); for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) From 3001ae7f94672064ca5db1a9f425644e98c3ecc6 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:17:15 +0000 Subject: [PATCH 20/34] Implement wfcheck for const parameters Co-Authored-By: Gabriel Smith --- src/librustc_typeck/check/wfcheck.rs | 59 +++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 860fa526a1b91..16cf25f0d4916 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -6,6 +6,7 @@ use rustc::traits::{self, ObligationCauseCode}; use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable, ToPredicate}; use rustc::ty::subst::{Subst, InternalSubsts}; use rustc::util::nodemap::{FxHashSet, FxHashMap}; +use rustc::mir::interpret::ConstValue; use rustc::middle::lang_items; use rustc::infer::opaque_types::may_define_existential_type; @@ -436,7 +437,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( // struct Foo> { .. } // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. for param in &generics.params { - if let GenericParamDefKind::Type {..} = param.kind { + if let GenericParamDefKind::Type { .. } = param.kind { if is_our_default(¶m) { let ty = fcx.tcx.type_of(param.def_id); // ignore dependent defaults -- that is, where the default of one type @@ -464,7 +465,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( // All regions are identity. fcx.tcx.mk_param_from_def(param) } - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Type { .. } => { // If the param has a default, if is_our_default(param) { let default_ty = fcx.tcx.type_of(param.def_id); @@ -477,6 +478,10 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( // Mark unwanted params as err. fcx.tcx.types.err.into() } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + fcx.tcx.types.err.into() + } } }); // Now we build the substituted predicates. @@ -497,6 +502,16 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( fn visit_region(&mut self, _: ty::Region<'tcx>) -> bool { true } + + fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool { + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Param(param), + .. + }) = c { + self.params.insert(param.index); + } + c.super_visit_with(self) + } } let mut param_count = CountParams::default(); let has_region = pred.visit_with(&mut param_count); @@ -617,11 +632,10 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( for (subst, param) in substs.iter().zip(&generics.params) { match subst.unpack() { ty::subst::UnpackedKind::Type(ty) => match ty.sty { - ty::Param(..) => {}, + ty::Param(..) => {} // prevent `fn foo() -> Foo` from being defining _ => { - tcx - .sess + tcx.sess .struct_span_err( span, "non-defining existential type use \ @@ -636,8 +650,9 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( ), ) .emit(); - }, - }, // match ty + } + } + ty::subst::UnpackedKind::Lifetime(region) => { let param_span = tcx.def_span(param.def_id); if let ty::ReStatic = region { @@ -658,7 +673,31 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( } else { seen.entry(region).or_default().push(param_span); } - }, + } + + ty::subst::UnpackedKind::Const(ct) => match ct { + ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Param(_), + .. + }) => {} + _ => { + tcx.sess + .struct_span_err( + span, + "non-defining existential type use \ + in defining scope", + ) + .span_note( + tcx.def_span(param.def_id), + &format!( + "used non-generic const {} for \ + generic parameter", + ty, + ), + ) + .emit(); + } + } } // match subst } // for (subst, param) for (_, spans) in seen { @@ -942,7 +981,9 @@ fn reject_shadowing_parameters(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) { let parent = tcx.generics_of(generics.parent.unwrap()); let impl_params: FxHashMap<_, _> = parent.params.iter().flat_map(|param| match param.kind { GenericParamDefKind::Lifetime => None, - GenericParamDefKind::Type {..} => Some((param.name, param.def_id)), + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { + Some((param.name, param.def_id)) + } }).collect(); for method_param in &generics.params { From eb2b8be6a0dfc2b3d1e2e83e501d0a40b0a3469e Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:17:35 +0000 Subject: [PATCH 21/34] Implement collect for const parameters Co-Authored-By: Gabriel Smith --- src/librustc_typeck/collect.rs | 235 +++++++++++++++++++++------------ 1 file changed, 150 insertions(+), 85 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 594e29ab9ddea..20b1ab4478a7c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1004,67 +1004,65 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty ast_generics .params .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Type { - ref default, - synthetic, - .. - } => { - if param.name.ident().name == keywords::SelfUpper.name() { - span_bug!( - param.span, - "`Self` should not be the name of a regular parameter" - ); - } - - if !allow_defaults && default.is_some() { - if !tcx.features().default_type_parameter_fallback { - tcx.lint_hir( - lint::builtin::INVALID_TYPE_PARAM_DEFAULT, - param.hir_id, + .filter_map(|param| { + let kind = match param.kind { + GenericParamKind::Type { + ref default, + synthetic, + .. + } => { + if param.name.ident().name == keywords::SelfUpper.name() { + span_bug!( param.span, - &format!( - "defaults for type parameters are only allowed in \ - `struct`, `enum`, `type`, or `trait` definitions." - ), + "`Self` should not be the name of a regular parameter" ); } - } - let ty_param = ty::GenericParamDef { - index: type_start + i as u32, - name: param.name.ident().as_interned_str(), - def_id: tcx.hir().local_def_id_from_hir_id(param.hir_id), - pure_wrt_drop: param.pure_wrt_drop, - kind: ty::GenericParamDefKind::Type { + if !allow_defaults && default.is_some() { + if !tcx.features().default_type_parameter_fallback { + tcx.lint_node( + lint::builtin::INVALID_TYPE_PARAM_DEFAULT, + param.hir_id, + param.span, + &format!( + "defaults for type parameters are only allowed in \ + `struct`, `enum`, `type`, or `trait` definitions." + ), + ); + } + } + + ty::GenericParamDefKind::Type { has_default: default.is_some(), object_lifetime_default: object_lifetime_defaults .as_ref() .map_or(rl::Set1::Empty, |o| o[i]), synthetic, - }, - }; - i += 1; - Some(ty_param) - } - GenericParamKind::Const { .. } => { - if param.name.ident().name == keywords::SelfUpper.name() { - span_bug!( - param.span, - "`Self` should not be the name of a regular parameter", - ); + } } + GenericParamKind::Const { .. } => { + if param.name.ident().name == keywords::SelfUpper.name() { + span_bug!( + param.span, + "`Self` should not be the name of a regular parameter", + ); + } - // Emit an error, but skip the parameter rather than aborting to - // continue to get other errors. - tcx.sess.struct_span_err( - param.span, - "const generics in any position are currently unsupported", - ).emit(); - None - } - _ => None, - }), + ty::GenericParamDefKind::Const + } + _ => return None, + }; + + let param_def = ty::GenericParamDef { + index: type_start + i as u32, + name: param.name.ident().as_interned_str(), + def_id: tcx.hir().local_def_id_from_hir_id(param.hir_id), + pure_wrt_drop: param.pure_wrt_drop, + kind, + }; + i += 1; + Some(param_def) + }) ); // provide junk type parameter defs - the only place that @@ -1284,44 +1282,111 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { tcx.mk_closure(def_id, substs) } - Node::AnonConst(_) => match tcx.hir().get_by_hir_id( - tcx.hir().get_parent_node_by_hir_id(hir_id)) - { - Node::Ty(&hir::Ty { - node: hir::TyKind::Array(_, ref constant), - .. - }) - | Node::Ty(&hir::Ty { - node: hir::TyKind::Typeof(ref constant), - .. - }) - | Node::Expr(&hir::Expr { - node: ExprKind::Repeat(_, ref constant), - .. - }) if constant.hir_id == hir_id => - { - tcx.types.usize - } + Node::AnonConst(_) => { + let parent_node = tcx.hir().get_by_hir_id(tcx.hir().get_parent_node_by_hir_id(hir_id)); + match parent_node { + Node::Ty(&hir::Ty { + node: hir::TyKind::Array(_, ref constant), + .. + }) + | Node::Ty(&hir::Ty { + node: hir::TyKind::Typeof(ref constant), + .. + }) + | Node::Expr(&hir::Expr { + node: ExprKind::Repeat(_, ref constant), + .. + }) if constant.hir_id == hir_id => + { + tcx.types.usize + } - Node::Variant(&Spanned { - node: - VariantKind { - disr_expr: Some(ref e), - .. - }, - .. - }) if e.hir_id == hir_id => - { - tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id)) - .repr - .discr_type() - .to_ty(tcx) - } + Node::Variant(&Spanned { + node: + VariantKind { + disr_expr: Some(ref e), + .. + }, + .. + }) if e.hir_id == hir_id => + { + tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id)) + .repr + .discr_type() + .to_ty(tcx) + } - x => { - bug!("unexpected const parent in type_of_def_id(): {:?}", x); + Node::Ty(&hir::Ty { node: hir::TyKind::Path(_), .. }) | + Node::Expr(&hir::Expr { node: ExprKind::Struct(..), .. }) | + Node::Expr(&hir::Expr { node: ExprKind::Path(_), .. }) => { + let path = match parent_node { + Node::Ty(&hir::Ty { node: hir::TyKind::Path(ref path), .. }) | + Node::Expr(&hir::Expr { node: ExprKind::Path(ref path), .. }) => { + path + } + Node::Expr(&hir::Expr { node: ExprKind::Struct(ref path, ..), .. }) => { + &*path + } + _ => unreachable!(), + }; + + match path { + QPath::Resolved(_, ref path) => { + let mut arg_index = 0; + let mut found_const = false; + for seg in &path.segments { + if let Some(generic_args) = &seg.args { + let args = &generic_args.args; + for arg in args { + if let GenericArg::Const(ct) = arg { + if ct.value.id == node_id { + found_const = true; + break; + } + arg_index += 1; + } + } + } + } + // Sanity check to make sure everything is as expected. + if !found_const { + bug!("no arg matching AnonConst in path") + } + match path.def { + // We've encountered an `AnonConst` in some path, so we need to + // figure out which generic parameter it corresponds to and return + // the relevant type. + Def::Struct(def_id) + | Def::Union(def_id) + | Def::Enum(def_id) + | Def::Fn(def_id) => { + let generics = tcx.generics_of(def_id); + let mut param_index = 0; + for param in &generics.params { + if let ty::GenericParamDefKind::Const = param.kind { + if param_index == arg_index { + return tcx.type_of(param.def_id); + } + param_index += 1; + } + } + // This is no generic parameter associated with the arg. This is + // probably from an extra arg where one is not needed. + return tcx.types.err; + } + Def::Err => tcx.types.err, + x => bug!("unexpected const parent path def {:?}", x), + } + } + x => bug!("unexpected const parent path {:?}", x), + } + } + + x => { + bug!("unexpected const parent in type_of_def_id(): {:?}", x); + } } - }, + } Node::GenericParam(param) => match ¶m.kind { hir::GenericParamKind::Type { default: Some(ref ty), .. } | From fc0fbe8bb5644a26d9ec17ce1d97e7cea85e76f9 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:18:04 +0000 Subject: [PATCH 22/34] Stub rustdoc const generics implementations Co-Authored-By: Gabriel Smith --- src/librustdoc/clean/mod.rs | 9 +++++++++ src/librustdoc/core.rs | 3 +++ 2 files changed, 12 insertions(+) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c64a73fa308e1..5d0d76507bd07 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1482,6 +1482,9 @@ impl<'tcx> Clean for ty::GenericParamDef { synthetic: None, }) } + ty::GenericParamDefKind::Const { .. } => { + unimplemented!() // FIXME(const_generics) + } }; GenericParamDef { @@ -1629,6 +1632,9 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, } Some(param.clean(cx)) } + ty::GenericParamDefKind::Const { .. } => { + unimplemented!() // FIXME(const_generics) + } }).collect::>(); let mut where_predicates = preds.predicates.iter() @@ -1678,6 +1684,9 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, .flat_map(|param| match param.kind { ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)), ty::GenericParamDefKind::Type { .. } => None, + ty::GenericParamDefKind::Const { .. } => { + unimplemented!() // FIXME(const_generics) + } }).chain(simplify::ty_params(stripped_typarams).into_iter()) .collect(), where_predicates: simplify::where_clauses(cx, where_predicates), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index fdb071638b799..07cfdde4a4e9d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -221,6 +221,9 @@ impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> { ty::GenericParamDefKind::Type { .. } => { args.push(hir::GenericArg::Type(self.ty_param_to_ty(param.clone()))); } + ty::GenericParamDefKind::Const { .. } => { + unimplemented!() // FIXME(const_generics) + } } } From 133e776bf007c78c36c85d790fcd7c62f1d58ce0 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:18:30 +0000 Subject: [PATCH 23/34] Add HAS_CT_INFER Co-Authored-By: Gabriel Smith --- src/librustc/ty/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index bd3dd78c9bb67..a649e312b4345 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -54,14 +54,14 @@ use crate::hir; pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST}; pub use self::sty::{FnSig, GenSig, CanonicalPolyFnSig, PolyFnSig, PolyGenSig}; -pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; +pub use self::sty::{InferTy, ParamTy, ParamConst, InferConst, ProjectionTy, ExistentialPredicate}; pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut}; pub use self::sty::{TraitRef, TyKind, PolyTraitRef}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const, LazyConst}; pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::RegionKind; -pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid}; +pub use self::sty::{TyVid, IntVid, FloatVid, ConstVid, RegionVid}; pub use self::sty::BoundRegion::*; pub use self::sty::InferTy::*; pub use self::sty::RegionKind::*; @@ -451,6 +451,8 @@ bitflags! { const HAS_TY_PLACEHOLDER = 1 << 14; + const HAS_CT_INFER = 1 << 15; + const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | TypeFlags::HAS_SELF.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits; @@ -462,6 +464,7 @@ bitflags! { TypeFlags::HAS_SELF.bits | TypeFlags::HAS_TY_INFER.bits | TypeFlags::HAS_RE_INFER.bits | + TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_RE_PLACEHOLDER.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits | TypeFlags::HAS_FREE_REGIONS.bits | From 2dfde8843885aec59c4cf90a424bf56e3658fc9e Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:18:43 +0000 Subject: [PATCH 24/34] Implement structural_impls for const generics Co-Authored-By: Gabriel Smith --- src/librustc/ty/structural_impls.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index f1a465e1f1724..f9eb336a4a3e2 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -5,12 +5,13 @@ use crate::mir::ProjectionKind; use crate::mir::interpret::ConstValue; -use crate::ty::{self, Lift, Ty, TyCtxt}; +use crate::ty::{self, Lift, Ty, TyCtxt, ConstVid, InferConst}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use smallvec::SmallVec; use crate::mir::interpret; +use std::marker::PhantomData; use std::rc::Rc; /////////////////////////////////////////////////////////////////////////// @@ -49,6 +50,7 @@ CloneTypeFoldableAndLiftImpls! { crate::ty::BoundRegion, crate::ty::ClosureKind, crate::ty::IntVarValue, + crate::ty::ParamConst, crate::ty::ParamTy, crate::ty::UniverseIndex, crate::ty::Variance, @@ -503,6 +505,14 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { type Lifted = ConstValue<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { match *self { + ConstValue::Param(param) => Some(ConstValue::Param(param)), + ConstValue::Infer(infer) => { + Some(ConstValue::Infer(match infer { + InferConst::Var(vid) => InferConst::Var(vid.lift_to_tcx(tcx)?), + InferConst::Fresh(i) => InferConst::Fresh(i), + InferConst::Canonical(debrujin, var) => InferConst::Canonical(debrujin, var), + })) + } ConstValue::Scalar(x) => Some(ConstValue::Scalar(x)), ConstValue::Slice(x, y) => Some(ConstValue::Slice(x, y)), ConstValue::ByRef(ptr, alloc) => Some(ConstValue::ByRef( @@ -512,6 +522,16 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ConstVid<'a> { + type Lifted = ConstVid<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, _: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + Some(ConstVid { + index: self.index, + phantom: PhantomData, + }) + } +} + /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. // From 8e56729b4da52c56c51bbabf35c3999578d0b098 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:19:13 +0000 Subject: [PATCH 25/34] Handle new ConstValue variants in mir Co-Authored-By: Gabriel Smith --- .../nll/region_infer/error_reporting/region_name.rs | 9 ++++++++- .../borrow_check/nll/type_check/constraint_conversion.rs | 5 +++++ src/librustc_mir/borrow_check/nll/type_check/mod.rs | 2 +- src/librustc_mir/interpret/operand.rs | 2 ++ src/librustc_mir/shim.rs | 9 ++------- src/librustc_mir/transform/check_unsafety.rs | 5 +++-- src/librustc_mir/transform/inline.rs | 2 +- 7 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index cc01f632e075c..fdede054e15f3 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -604,7 +604,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { search_stack.push((ty, hir_ty)); } - (UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => { + (UnpackedKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => { + // Lifetimes cannot be found in consts, so we don't need + // to search anything here. + } + + (UnpackedKind::Lifetime(_), _) + | (UnpackedKind::Type(_), _) + | (UnpackedKind::Const(_), _) => { // I *think* that HIR lowering should ensure this // doesn't happen, even in erroneous // programs. Else we should use delay-span-bug. diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 1a72205ad7ae1..bef159e996b87 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -99,6 +99,11 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { param_env, ).type_must_outlive(origin, t1, r2); } + + UnpackedKind::Const(_) => { + // Consts cannot outlive one another, so we + // don't need to handle any relations here. + } } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index cc03d4a0c9643..5b444ab9690ca 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -2533,7 +2533,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ), )) } - UnpackedKind::Type(_) => None, + UnpackedKind::Type(_) | UnpackedKind::Const(_) => None, } }) .collect(); diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 979595d6c0009..574506ed2329d 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -594,6 +594,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> self.layout_of(ty) })?; let op = match val.val { + ConstValue::Param(_) => Err(EvalErrorKind::TooGeneric.into()), + ConstValue::Infer(_) => bug!(), ConstValue::ByRef(ptr, alloc) => { // We rely on mutability being set correctly in that allocation to prevent writes // where none should happen -- and for `static mut`, we copy on demand anyway. diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index db8476f3be5f7..1c6b1450be862 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -2,7 +2,7 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer; use rustc::mir::*; -use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::VariantIdx; use rustc::ty::subst::{Subst, InternalSubsts}; use rustc::ty::query::Providers; @@ -450,12 +450,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ) { let tcx = self.tcx; - let substs = InternalSubsts::for_item(tcx, self.def_id, |param, _| { - match param.kind { - GenericParamDefKind::Lifetime => tcx.types.re_erased.into(), - GenericParamDefKind::Type {..} => ty.into(), - } - }); + let substs = tcx.mk_substs_trait(ty, &[]); // `func == Clone::clone(&ty) -> ty` let func_ty = tcx.mk_fn_def(self.def_id, substs); diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index a8816720b28bd..047731e3fe6a7 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -558,9 +558,10 @@ fn unsafe_derive_on_repr_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: D // FIXME: when we make this a hard error, this should have its // own error code. - let message = if tcx.generics_of(def_id).own_counts().types != 0 { + let counts = tcx.generics_of(def_id).own_counts(); + let message = if counts.types + counts.consts != 0 { "#[derive] can't be used on a #[repr(packed)] struct with \ - type parameters (error E0133)".to_string() + type or const parameters (error E0133)".to_string() } else { "#[derive] can't be used on a #[repr(packed)] struct that \ does not derive Copy (error E0133)".to_string() diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 4cdef015b53ff..918375e426b7d 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -259,7 +259,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // inlining. This is to ensure that the final crate doesn't have MIR that // reference unexported symbols if callsite.callee.is_local() { - if callsite.substs.types().count() == 0 && !hinted { + if callsite.substs.non_erasable_generics().count() == 0 && !hinted { debug!(" callee is an exported function - not inlining"); return false; } From c236c241e66c786f1d585aec62744d4995b6227b Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:19:42 +0000 Subject: [PATCH 26/34] Handle const generics in typeck Co-Authored-By: Gabriel Smith --- src/librustc_typeck/check/closure.rs | 10 +++++---- src/librustc_typeck/check/dropck.rs | 3 +++ src/librustc_typeck/check/method/confirm.rs | 3 +++ src/librustc_typeck/check/method/mod.rs | 4 ++-- src/librustc_typeck/check/method/probe.rs | 10 +++++++-- src/librustc_typeck/check/mod.rs | 22 ++++++++++++++++++- .../constrained_type_params.rs | 15 +++++++++++++ src/librustc_typeck/impl_wf_check.rs | 11 +++++++++- src/librustc_typeck/outlives/mod.rs | 22 +++++++++++++------ src/librustc_typeck/outlives/utils.rs | 4 ++++ 10 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index db89b32be7b68..f7396cbd42f2f 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -99,11 +99,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let substs = base_substs.extend_to(self.tcx,expr_def_id, |param, _| { match param.kind { GenericParamDefKind::Lifetime => { - span_bug!(expr.span, "closure has region param") + span_bug!(expr.span, "closure has lifetime param") } - GenericParamDefKind::Type {..} => { - self.infcx - .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)).into() + GenericParamDefKind::Type { .. } => { + self.infcx.next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)).into() + } + GenericParamDefKind::Const => { + span_bug!(expr.span, "closure has const param") } } }); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 12c7484f0f921..2184555a07d34 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -313,6 +313,9 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( match kind.unpack() { UnpackedKind::Lifetime(r) => rcx.sub_regions(origin(), parent_scope, r), UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope), + UnpackedKind::Const(_) => { + // Generic consts don't add constraints. + } } } Ok(()) diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 996d6cfd56830..e0b96ae884f3a 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -341,6 +341,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.to_ty(ty).into() } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into() + } _ => unreachable!(), } }, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index d81d24e6d2b03..8f27b5b7dc81f 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -283,8 +283,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Construct a trait-reference `self_ty : Trait` let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { match param.kind { - GenericParamDefKind::Lifetime => {} - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => {} + GenericParamDefKind::Type { .. } => { if param.index == 0 { return self_ty.into(); } else if let Some(ref input_types) = opt_input_types { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index a4624eebcba83..efae870c3c3a9 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1528,7 +1528,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // `impl_self_ty()` for an explanation. self.tcx.types.re_erased.into() } - GenericParamDefKind::Type {..} => self.var_for_def(self.span, param), + GenericParamDefKind::Type { .. } + | GenericParamDefKind::Const => { + self.var_for_def(self.span, param) + } } } }); @@ -1545,10 +1548,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { InternalSubsts::for_item(self.tcx, def_id, |param, _| { match param.kind { GenericParamDefKind::Lifetime => self.tcx.types.re_erased.into(), - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Type { .. } => { self.next_ty_var(TypeVariableOrigin::SubstitutionPlaceholder( self.tcx.def_span(def_id))).into() } + GenericParamDefKind::Const { .. } => { + unimplemented!() // FIXME(const_generics) + } } }) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 183667e224462..301d7d3ac5623 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2437,6 +2437,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } + pub fn to_const(&self, ast_c: &hir::AnonConst, ty: Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + AstConv::ast_const_to_const(self, ast_c, ty) + } + // If the type given by the user has free regions, save it for later, since // NLL would like to enforce those. Also pass in types that involve // projections, since those can resolve to `'static` bounds (modulo #54940, @@ -5501,6 +5505,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.to_ty(ty).into() } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into() + } _ => unreachable!(), } }, @@ -5528,6 +5535,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.var_for_def(span, param) } } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + // No const parameters were provided, we have to infer them. + self.var_for_def(span, param) + } } }, ); @@ -5685,11 +5697,19 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) { let own_counts = generics.own_counts(); - debug!("check_bounds_are_used(n_tps={}, ty={:?})", own_counts.types, ty); + debug!( + "check_bounds_are_used(n_tys={}, n_cts={}, ty={:?})", + own_counts.types, + own_counts.consts, + ty + ); + + // FIXME(const_generics): we probably want to check the bounds for const parameters too. if own_counts.types == 0 { return; } + // Make a vector of booleans initially false, set to true when used. let mut types_used = vec![false; own_counts.types]; diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 6a530f454d2b3..4b922c3403886 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -1,6 +1,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::fold::{TypeFoldable, TypeVisitor}; use rustc::util::nodemap::FxHashSet; +use rustc::mir::interpret::ConstValue; use syntax::source_map::Span; #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -14,6 +15,10 @@ impl From for Parameter { fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) } } +impl From for Parameter { + fn from(param: ty::ParamConst) -> Self { Parameter(param.index) } +} + /// Returns the set of parameters constrained by the impl header. pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>, impl_trait_ref: Option>) @@ -72,6 +77,16 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { } false } + + fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool { + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Param(data), + .. + }) = c { + self.parameters.push(Parameter::from(*data)); + } + false + } } pub fn identify_constrained_type_params<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index b79277ffbbce8..5677f2c94d8e2 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -120,7 +120,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for param in &impl_generics.params { match param.kind { // Disallow ANY unconstrained type parameters. - ty::GenericParamDefKind::Type {..} => { + ty::GenericParamDefKind::Type { .. } => { let param_ty = ty::ParamTy::for_def(param); if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { report_unused_parameter(tcx, @@ -139,6 +139,15 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ¶m.name.to_string()); } } + ty::GenericParamDefKind::Const => { + let param_ct = ty::ParamConst::for_def(param); + if !input_parameters.contains(&ctp::Parameter::from(param_ct)) { + report_unused_parameter(tcx, + tcx.def_span(param.def_id), + "const", + ¶m_ct.to_string()); + } + } } } diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index b3634d37cc2b8..1ab414c1f015f 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -98,14 +98,22 @@ fn inferred_outlives_crate<'tcx>( .map(|(&def_id, set)| { let vec: Vec> = set .iter() - .map( + .filter_map( |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() { - UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder::bind( - ty::OutlivesPredicate(ty1, region2), - )), - UnpackedKind::Lifetime(region1) => ty::Predicate::RegionOutlives( - ty::Binder::bind(ty::OutlivesPredicate(region1, region2)), - ), + UnpackedKind::Type(ty1) => { + Some(ty::Predicate::TypeOutlives(ty::Binder::bind( + ty::OutlivesPredicate(ty1, region2) + ))) + } + UnpackedKind::Lifetime(region1) => { + Some(ty::Predicate::RegionOutlives( + ty::Binder::bind(ty::OutlivesPredicate(region1, region2)) + )) + } + UnpackedKind::Const(_) => { + // Generic consts don't impose any constraints. + None + } }, ).collect(); (def_id, Lrc::new(vec)) diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs index c886c7a4ffce5..ee552ca9cbb25 100644 --- a/src/librustc_typeck/outlives/utils.rs +++ b/src/librustc_typeck/outlives/utils.rs @@ -118,6 +118,10 @@ pub fn insert_outlives_predicate<'tcx>( } required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region)); } + + UnpackedKind::Const(_) => { + // Generic consts don't impose any constraints. + } } } From 54b935b9b99a8cf276bc55906b9817f8cf44bfbb Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:20:06 +0000 Subject: [PATCH 27/34] Handle const generics elsewhere Co-Authored-By: Gabriel Smith --- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc/traits/error_reporting.rs | 3 ++- src/librustc/traits/mod.rs | 3 ++- src/librustc/traits/object_safety.rs | 3 ++- src/librustc/traits/on_unimplemented.rs | 3 ++- src/librustc/ty/relate.rs | 3 +++ src/librustc/ty/util.rs | 20 ++++++++++++++++---- src/librustc_privacy/lib.rs | 10 ++++++++-- src/librustc_traits/chalk_context/mod.rs | 13 ++++++++++++- 9 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 2618d0874cbc3..d2bec1070f921 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -1974,7 +1974,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { object_lifetime_default, .. } => Some(object_lifetime_default), - GenericParamDefKind::Lifetime => None, + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, }) .collect() }) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3eb49092fed1d..322e384e13e20 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -389,7 +389,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { for param in generics.params.iter() { let value = match param.kind { - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Type { .. } | + GenericParamDefKind::Const => { trait_ref.substs[param.index as usize].to_string() }, GenericParamDefKind::Lifetime => continue, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index ee7893a27de7d..32bb7f186938a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -1010,7 +1010,8 @@ fn vtable_methods<'a, 'tcx>( InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { GenericParamDefKind::Lifetime => tcx.types.re_erased.into(), - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Type { .. } | + GenericParamDefKind::Const => { trait_ref.substs[param.index as usize] } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index b2079c2516935..e7a5138e6893c 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -310,7 +310,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } // We can't monomorphize things like `fn foo(...)`. - if self.generics_of(method.def_id).own_counts().types != 0 { + let own_counts = self.generics_of(method.def_id).own_counts(); + if own_counts.types + own_counts.consts != 0 { return Some(MethodViolationCode::Generic); } diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index f61c32614cc93..c86fd0d52b901 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -280,7 +280,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { let generics = tcx.generics_of(trait_ref.def_id); let generic_map = generics.params.iter().filter_map(|param| { let value = match param.kind { - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Type { .. } | + GenericParamDefKind::Const => { trait_ref.substs[param.index as usize].to_string() }, GenericParamDefKind::Lifetime => return None diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 2940757fa905b..3a31801b3be39 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -705,6 +705,9 @@ impl<'tcx> Relate<'tcx> for Kind<'tcx> { (UnpackedKind::Type(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } + (UnpackedKind::Const(_), _) => { + unimplemented!() // FIXME(const_generics) + } } } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 4ad3ffaa93da4..fb0d1e2080b06 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -12,6 +12,7 @@ use crate::ty::subst::{Subst, InternalSubsts, SubstsRef, UnpackedKind}; use crate::ty::query::TyCtxtAt; use crate::ty::TyKind::*; use crate::ty::layout::{Integer, IntegerExt}; +use crate::mir::interpret::ConstValue; use crate::util::common::ErrorReported; use crate::middle::lang_items; @@ -495,8 +496,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) => { !impl_generics.type_param(pt, self).pure_wrt_drop } - UnpackedKind::Lifetime(_) | UnpackedKind::Type(_) => { - // not a type or region param - this should be reported + UnpackedKind::Const(&ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Param(ref pc), + .. + })) => { + !impl_generics.const_param(pc, self).pure_wrt_drop + } + UnpackedKind::Lifetime(_) | + UnpackedKind::Type(_) | + UnpackedKind::Const(_) => { + // Not a type, const or region param: this should be reported // as an error. false } @@ -587,15 +596,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Some(ty::Binder::bind(env_ty)) } - /// Given the `DefId` of some item that has no type parameters, make + /// Given the `DefId` of some item that has no type or const parameters, make /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> SubstsRef<'tcx> { InternalSubsts::for_item(self, item_def_id, |param, _| { match param.kind { GenericParamDefKind::Lifetime => self.types.re_erased.into(), - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Type { .. } => { bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) } + GenericParamDefKind::Const { .. } => { + bug!("empty_substs_for_def_id: {:?} has const parameters", item_def_id) + } } }) } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 550b333700b04..a9f05eb60db18 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -748,12 +748,15 @@ impl<'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> { fn generics(&mut self) -> &mut Self { for param in &self.ev.tcx.generics_of(self.item_def_id).params { match param.kind { + GenericParamDefKind::Lifetime => {} GenericParamDefKind::Type { has_default, .. } => { if has_default { self.visit(self.ev.tcx.type_of(param.def_id)); } } - GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Const => { + self.visit(self.ev.tcx.type_of(param.def_id)); + } } } self @@ -1517,12 +1520,15 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { fn generics(&mut self) -> &mut Self { for param in &self.tcx.generics_of(self.item_def_id).params { match param.kind { + GenericParamDefKind::Lifetime => {} GenericParamDefKind::Type { has_default, .. } => { if has_default { self.visit(self.tcx.type_of(param.def_id)); } } - GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Const => { + self.visit(self.tcx.type_of(param.def_id)); + } } } self diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs index a326d84725ab4..6420f20a3ea29 100644 --- a/src/librustc_traits/chalk_context/mod.rs +++ b/src/librustc_traits/chalk_context/mod.rs @@ -32,11 +32,12 @@ use rustc::traits::{ InEnvironment, ChalkCanonicalGoal, }; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, InferConst}; use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc::ty::query::Providers; use rustc::ty::subst::{Kind, UnpackedKind}; use rustc_data_structures::sync::Lrc; +use rustc::mir::interpret::ConstValue; use syntax_pos::DUMMY_SP; use std::fmt::{self, Debug}; @@ -287,6 +288,16 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { } _ => false, }, + UnpackedKind::Const(ct) => match ct { + ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)), + .. + }) => { + debug_assert_eq!(*debruijn, ty::INNERMOST); + cvar == *bound_ct + } + _ => false, + } }) } From 4c18ee4abd572ad778aee89e2bee17e7d097f31e Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:20:22 +0000 Subject: [PATCH 28/34] Update const generics tests Co-Authored-By: Gabriel Smith --- .../const-expression-parameter.rs | 3 ++- .../const-expression-parameter.stderr | 15 +++++++++------ .../const-fn-with-const-param.rs | 1 - .../const-fn-with-const-param.stderr | 9 +-------- .../const-param-before-other-params.rs | 4 +--- .../const-param-before-other-params.stderr | 18 +++--------------- .../const-param-from-outer-fn.rs | 1 - .../const-param-from-outer-fn.stderr | 11 ++--------- .../const-parameter-uppercase-lint.rs | 4 +++- .../const-parameter-uppercase-lint.stderr | 17 +++++++++-------- 10 files changed, 30 insertions(+), 53 deletions(-) diff --git a/src/test/ui/const-generics/const-expression-parameter.rs b/src/test/ui/const-generics/const-expression-parameter.rs index f4e9008dbd0f1..0883caa5c7075 100644 --- a/src/test/ui/const-generics/const-expression-parameter.rs +++ b/src/test/ui/const-generics/const-expression-parameter.rs @@ -2,7 +2,6 @@ //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash fn u32_identity() -> u32 { - //~^ ERROR const generics in any position are currently unsupported 5 } @@ -16,6 +15,8 @@ fn foo_b() { fn foo_c() { u32_identity::< -1 >(); // ok + // FIXME(const_generics) + //~^^ ERROR cannot apply unary operator `-` to type `u32` [E0600] } fn main() { diff --git a/src/test/ui/const-generics/const-expression-parameter.stderr b/src/test/ui/const-generics/const-expression-parameter.stderr index 1dd3a960316d9..8871aa45788e1 100644 --- a/src/test/ui/const-generics/const-expression-parameter.stderr +++ b/src/test/ui/const-generics/const-expression-parameter.stderr @@ -1,11 +1,11 @@ error: expected identifier, found `<-` - --> $DIR/const-expression-parameter.rs:10:19 + --> $DIR/const-expression-parameter.rs:9:19 | LL | u32_identity::<-1>(); //~ ERROR expected identifier, found `<-` | ^^ expected identifier error: expected one of `,` or `>`, found `+` - --> $DIR/const-expression-parameter.rs:14:22 + --> $DIR/const-expression-parameter.rs:13:22 | LL | u32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+` | ^ expected one of `,` or `>` here @@ -16,11 +16,14 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error: const generics in any position are currently unsupported - --> $DIR/const-expression-parameter.rs:4:23 +error[E0600]: cannot apply unary operator `-` to type `u32` + --> $DIR/const-expression-parameter.rs:17:21 | -LL | fn u32_identity() -> u32 { - | ^ +LL | u32_identity::< -1 >(); // ok + | ^^ cannot apply unary operator `-` + | + = note: unsigned values cannot be negated error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0600`. diff --git a/src/test/ui/const-generics/const-fn-with-const-param.rs b/src/test/ui/const-generics/const-fn-with-const-param.rs index 052d723d96edb..f36bf3875c349 100644 --- a/src/test/ui/const-generics/const-fn-with-const-param.rs +++ b/src/test/ui/const-generics/const-fn-with-const-param.rs @@ -3,7 +3,6 @@ const fn const_u32_identity() -> u32 { //~^ ERROR const parameters are not permitted in `const fn` - //~^^ ERROR const generics in any position are currently unsupported X } diff --git a/src/test/ui/const-generics/const-fn-with-const-param.stderr b/src/test/ui/const-generics/const-fn-with-const-param.stderr index a08ebfb0d9766..94d2afa25b4f0 100644 --- a/src/test/ui/const-generics/const-fn-with-const-param.stderr +++ b/src/test/ui/const-generics/const-fn-with-const-param.stderr @@ -9,16 +9,9 @@ error: const parameters are not permitted in `const fn` | LL | / const fn const_u32_identity() -> u32 { LL | | //~^ ERROR const parameters are not permitted in `const fn` -LL | | //~^^ ERROR const generics in any position are currently unsupported LL | | X LL | | } | |_^ -error: const generics in any position are currently unsupported - --> $DIR/const-fn-with-const-param.rs:4:35 - | -LL | const fn const_u32_identity() -> u32 { - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index 47f826789e03e..188b5dce31ea8 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,14 +1,12 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -fn foo(_: T) { +fn foo(_: &T) { //~^ ERROR type parameters must be declared prior to const parameters - //~^^ ERROR const generics in any position are currently unsupported } fn bar(_: &'a ()) { //~^ ERROR lifetime parameters must be declared prior to const parameters - //~^^ ERROR const generics in any position are currently unsupported } fn main() {} diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr index a43415d0e5a43..78f129e79ea24 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.stderr @@ -7,26 +7,14 @@ LL | #![feature(const_generics)] error: type parameters must be declared prior to const parameters --> $DIR/const-param-before-other-params.rs:4:21 | -LL | fn foo(_: T) { +LL | fn foo(_: &T) { | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` error: lifetime parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:9:21 + --> $DIR/const-param-before-other-params.rs:8:21 | LL | fn bar(_: &'a ()) { | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` -error: const generics in any position are currently unsupported - --> $DIR/const-param-before-other-params.rs:4:14 - | -LL | fn foo(_: T) { - | ^ - -error: const generics in any position are currently unsupported - --> $DIR/const-param-before-other-params.rs:9:14 - | -LL | fn bar(_: &'a ()) { - | ^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const-param-from-outer-fn.rs b/src/test/ui/const-generics/const-param-from-outer-fn.rs index 5a8dd92086f85..6534bcf5ce64c 100644 --- a/src/test/ui/const-generics/const-param-from-outer-fn.rs +++ b/src/test/ui/const-generics/const-param-from-outer-fn.rs @@ -2,7 +2,6 @@ //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash fn foo() { - //~^ ERROR const generics in any position are currently unsupported fn bar() -> u32 { X //~ ERROR can't use generic parameters from outer function } diff --git a/src/test/ui/const-generics/const-param-from-outer-fn.stderr b/src/test/ui/const-generics/const-param-from-outer-fn.stderr index b238b3a2aa453..f40b527d71607 100644 --- a/src/test/ui/const-generics/const-param-from-outer-fn.stderr +++ b/src/test/ui/const-generics/const-param-from-outer-fn.stderr @@ -5,22 +5,15 @@ LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ error[E0401]: can't use generic parameters from outer function - --> $DIR/const-param-from-outer-fn.rs:7:9 + --> $DIR/const-param-from-outer-fn.rs:6:9 | LL | fn foo() { | - const variable from outer function -LL | //~^ ERROR const generics in any position are currently unsupported LL | fn bar() -> u32 { | --- try adding a local generic parameter in this method instead LL | X //~ ERROR can't use generic parameters from outer function | ^ use of generic parameter from outer function -error: const generics in any position are currently unsupported - --> $DIR/const-param-from-outer-fn.rs:4:14 - | -LL | fn foo() { - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0401`. diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.rs b/src/test/ui/const-generics/const-parameter-uppercase-lint.rs index 37fe9af98b3df..164205dd75cbc 100644 --- a/src/test/ui/const-generics/const-parameter-uppercase-lint.rs +++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.rs @@ -4,5 +4,7 @@ #![deny(non_upper_case_globals)] fn noop() { - //~^ ERROR const generics in any position are currently unsupported + //~^ ERROR const parameter `x` should have an upper case name } + +fn main() {} diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr index 9683e91cef30c..190798d202bea 100644 --- a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr +++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr @@ -4,16 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error[E0601]: `main` function not found in crate `const_parameter_uppercase_lint` - | - = note: consider adding a `main` function to `$DIR/const-parameter-uppercase-lint.rs` - -error: const generics in any position are currently unsupported +error: const parameter `x` should have an upper case name --> $DIR/const-parameter-uppercase-lint.rs:6:15 | LL | fn noop() { - | ^ + | ^ help: convert the identifier to upper case: `X` + | +note: lint level defined here + --> $DIR/const-parameter-uppercase-lint.rs:4:9 + | +LL | #![deny(non_upper_case_globals)] + | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0601`. From 3e3a4212e8bf8fb52088906a0cbf6a2699c7f035 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 01:20:35 +0000 Subject: [PATCH 29/34] Update test fallout Co-Authored-By: Gabriel Smith --- .../ui/derives/deriving-with-repr-packed.stderr | 4 ++-- .../feature-gates/feature-gate-const_generics.rs | 2 -- .../feature-gate-const_generics.stderr | 16 ++-------------- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/test/ui/derives/deriving-with-repr-packed.stderr b/src/test/ui/derives/deriving-with-repr-packed.stderr index 4ab14a1df84db..9d96908a05620 100644 --- a/src/test/ui/derives/deriving-with-repr-packed.stderr +++ b/src/test/ui/derives/deriving-with-repr-packed.stderr @@ -1,4 +1,4 @@ -error: #[derive] can't be used on a #[repr(packed)] struct with type parameters (error E0133) +error: #[derive] can't be used on a #[repr(packed)] struct with type or const parameters (error E0133) --> $DIR/deriving-with-repr-packed.rs:8:16 | LL | #[derive(Copy, Clone, PartialEq, Eq)] @@ -12,7 +12,7 @@ LL | #![deny(safe_packed_borrows)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #46043 -error: #[derive] can't be used on a #[repr(packed)] struct with type parameters (error E0133) +error: #[derive] can't be used on a #[repr(packed)] struct with type or const parameters (error E0133) --> $DIR/deriving-with-repr-packed.rs:8:23 | LL | #[derive(Copy, Clone, PartialEq, Eq)] diff --git a/src/test/ui/feature-gates/feature-gate-const_generics.rs b/src/test/ui/feature-gates/feature-gate-const_generics.rs index 907e00b11e556..fe1ded1c4bbc4 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics.rs +++ b/src/test/ui/feature-gates/feature-gate-const_generics.rs @@ -1,7 +1,5 @@ fn foo() {} //~ ERROR const generics are unstable -//~^ const generics in any position are currently unsupported struct Foo([(); X]); //~ ERROR const generics are unstable -//~^ const generics in any position are currently unsupported fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_generics.stderr b/src/test/ui/feature-gates/feature-gate-const_generics.stderr index 3ab1aa2367f1c..bd86a4197a76e 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics.stderr @@ -7,25 +7,13 @@ LL | fn foo() {} //~ ERROR const generics are unstable = help: add #![feature(const_generics)] to the crate attributes to enable error[E0658]: const generics are unstable (see issue #44580) - --> $DIR/feature-gate-const_generics.rs:4:18 + --> $DIR/feature-gate-const_generics.rs:3:18 | LL | struct Foo([(); X]); //~ ERROR const generics are unstable | ^ | = help: add #![feature(const_generics)] to the crate attributes to enable -error: const generics in any position are currently unsupported - --> $DIR/feature-gate-const_generics.rs:1:14 - | -LL | fn foo() {} //~ ERROR const generics are unstable - | ^ - -error: const generics in any position are currently unsupported - --> $DIR/feature-gate-const_generics.rs:4:18 - | -LL | struct Foo([(); X]); //~ ERROR const generics are unstable - | ^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From 162405f2221439fc9410ecb60f3e5939c2f2fac8 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 11:01:39 +0000 Subject: [PATCH 30/34] Fix negative integer literal test Co-Authored-By: Gabriel Smith --- .../const-generics/const-expression-parameter.rs | 12 +++++------- .../const-expression-parameter.stderr | 15 +++------------ 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/test/ui/const-generics/const-expression-parameter.rs b/src/test/ui/const-generics/const-expression-parameter.rs index 0883caa5c7075..662c7b767bae0 100644 --- a/src/test/ui/const-generics/const-expression-parameter.rs +++ b/src/test/ui/const-generics/const-expression-parameter.rs @@ -1,24 +1,22 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -fn u32_identity() -> u32 { +fn i32_identity() -> i32 { 5 } fn foo_a() { - u32_identity::<-1>(); //~ ERROR expected identifier, found `<-` + i32_identity::<-1>(); //~ ERROR expected identifier, found `<-` } fn foo_b() { - u32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+` + i32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+` } fn foo_c() { - u32_identity::< -1 >(); // ok - // FIXME(const_generics) - //~^^ ERROR cannot apply unary operator `-` to type `u32` [E0600] + i32_identity::< -1 >(); // ok } fn main() { - u32_identity::<5>(); // ok + i32_identity::<5>(); // ok } diff --git a/src/test/ui/const-generics/const-expression-parameter.stderr b/src/test/ui/const-generics/const-expression-parameter.stderr index 8871aa45788e1..2741d62125622 100644 --- a/src/test/ui/const-generics/const-expression-parameter.stderr +++ b/src/test/ui/const-generics/const-expression-parameter.stderr @@ -1,13 +1,13 @@ error: expected identifier, found `<-` --> $DIR/const-expression-parameter.rs:9:19 | -LL | u32_identity::<-1>(); //~ ERROR expected identifier, found `<-` +LL | i32_identity::<-1>(); //~ ERROR expected identifier, found `<-` | ^^ expected identifier error: expected one of `,` or `>`, found `+` --> $DIR/const-expression-parameter.rs:13:22 | -LL | u32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+` +LL | i32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+` | ^ expected one of `,` or `>` here warning: the feature `const_generics` is incomplete and may cause the compiler to crash @@ -16,14 +16,5 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error[E0600]: cannot apply unary operator `-` to type `u32` - --> $DIR/const-expression-parameter.rs:17:21 - | -LL | u32_identity::< -1 >(); // ok - | ^^ cannot apply unary operator `-` - | - = note: unsigned values cannot be negated - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0600`. From 0da0457593c5c1cb09f6197782ca73617860e897 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 20 Feb 2019 12:47:19 +0000 Subject: [PATCH 31/34] Clean up some generic substs handling --- src/librustc/infer/opaque_types/mod.rs | 11 ++++++++--- src/librustc/infer/outlives/obligations.rs | 20 +++++++++++++------- src/librustc_typeck/check/regionck.rs | 22 ++++++++++++++-------- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 159bc1ceae26c..1b7ecc7c3a67c 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -381,10 +381,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { substs, item_def_id: _, }) => { - for r in substs.regions() { - bound_region(r); + for k in substs { + match k.unpack() { + UnpackedKind::Lifetime(lt) => bound_region(lt), + UnpackedKind::Type(ty) => types.push(ty), + UnpackedKind::Const(_) => { + // Const parameters don't impose constraints. + } + } } - types.extend(substs.types()); } Component::EscapingProjection(more_components) => { diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index bbda3d2fdbf84..ee66032848519 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -67,6 +67,7 @@ use crate::hir; use crate::traits::ObligationCause; use crate::ty::outlives::Component; use crate::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; +use crate::ty::subst::UnpackedKind; impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// Registers that the given region obligation must be resolved @@ -430,13 +431,18 @@ where if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer { debug!("projection_must_outlive: no declared bounds"); - for component_ty in projection_ty.substs.types() { - self.type_must_outlive(origin.clone(), component_ty, region); - } - - for r in projection_ty.substs.regions() { - self.delegate - .push_sub_region_constraint(origin.clone(), region, r); + for k in projection_ty.substs { + match k.unpack() { + UnpackedKind::Lifetime(lt) => { + self.delegate.push_sub_region_constraint(origin.clone(), region, lt); + } + UnpackedKind::Type(ty) => { + self.type_must_outlive(origin.clone(), ty, region); + } + UnpackedKind::Const(_) => { + // Const parameters don't impose constraints. + } + } } return; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b549986777c84..a03d33a3ef5bc 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -81,7 +81,7 @@ use rustc::hir::def_id::DefId; use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::infer::{self, RegionObligation, SuppressRegionErrors}; use rustc::ty::adjustment; -use rustc::ty::subst::SubstsRef; +use rustc::ty::subst::{SubstsRef, UnpackedKind}; use rustc::ty::{self, Ty}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; @@ -1407,13 +1407,19 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = infer::ParameterInScope(origin, expr_span); - for region in substs.regions() { - self.sub_regions(origin.clone(), expr_region, region); - } - - for ty in substs.types() { - let ty = self.resolve_type(ty); - self.type_must_outlive(origin.clone(), ty, expr_region); + for kind in substs { + match kind.unpack() { + UnpackedKind::Lifetime(lt) => { + self.sub_regions(origin.clone(), expr_region, lt); + } + UnpackedKind::Type(ty) => { + let ty = self.resolve_type(ty); + self.type_must_outlive(origin.clone(), ty, expr_region); + } + UnpackedKind::Const(_) => { + // Const parameters don't impose constraints. + } + } } } } From 5c8b3c38f1a5a0270b29fa01f14c9db0b255ea43 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 5 Mar 2019 22:31:06 +0000 Subject: [PATCH 32/34] Fix rebase fallout --- src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_typeck/astconv.rs | 6 +++--- src/librustc_typeck/collect.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 574506ed2329d..11b4aa17ec43f 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -594,7 +594,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> self.layout_of(ty) })?; let op = match val.val { - ConstValue::Param(_) => Err(EvalErrorKind::TooGeneric.into()), + ConstValue::Param(_) => return Err(EvalErrorKind::TooGeneric.into()), ConstValue::Infer(_) => bug!(), ConstValue::ByRef(ptr, alloc) => { // We rely on mutability being set correctly in that allocation to prevent writes diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1dec2d483b80f..be708c78a0dd1 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1869,14 +1869,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { ast_const: &hir::AnonConst, ty: Ty<'tcx> ) -> &'tcx ty::LazyConst<'tcx> { - debug!("ast_const_to_const(id={:?}, ast_const={:?})", ast_const.id, ast_const); + debug!("ast_const_to_const(id={:?}, ast_const={:?})", ast_const.hir_id, ast_const); let tcx = self.tcx(); - let def_id = tcx.hir().local_def_id(ast_const.id); + let def_id = tcx.hir().local_def_id_from_hir_id(ast_const.hir_id); let mut lazy_const = ty::LazyConst::Unevaluated( def_id, - Substs::identity_for_item(tcx, def_id) + InternalSubsts::identity_for_item(tcx, def_id), ); let expr = &tcx.hir().body(ast_const.body).value; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 20b1ab4478a7c..eb4bbe880693b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1020,7 +1020,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty if !allow_defaults && default.is_some() { if !tcx.features().default_type_parameter_fallback { - tcx.lint_node( + tcx.lint_hir( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, param.hir_id, param.span, @@ -1339,7 +1339,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { let args = &generic_args.args; for arg in args { if let GenericArg::Const(ct) = arg { - if ct.value.id == node_id { + if ct.value.hir_id == hir_id { found_const = true; break; } From ed9227abbdb14728777691c0d595a93c57a796bf Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 5 Mar 2019 22:49:37 +0000 Subject: [PATCH 33/34] Make adjustments for comments --- src/librustc_mir/interpret/operand.rs | 8 ++++++-- src/librustc_mir/monomorphize/collector.rs | 13 ++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 11b4aa17ec43f..1ebff41151011 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -593,9 +593,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let ty = self.monomorphize(val.ty)?; self.layout_of(ty) })?; - let op = match val.val { - ConstValue::Param(_) => return Err(EvalErrorKind::TooGeneric.into()), + let val = match val.val { + ConstValue::Param(_) => self.monomorphize(val)?.val, ConstValue::Infer(_) => bug!(), + val => val, + }; + let op = match val { + ConstValue::Param(_) | ConstValue::Infer(_) => unreachable!(), ConstValue::ByRef(ptr, alloc) => { // We rely on mutability being set correctly in that allocation to prevent writes // where none should happen -- and for `static mut`, we copy on demand anyway. diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 2ce3bf43cfc77..4350bfcdc7a96 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -467,14 +467,13 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let type_length = instance.substs.types().flat_map(|ty| ty.walk()).count(); let const_length = instance.substs.consts() - .filter_map(|ct| { - if let ty::LazyConst::Evaluated(ct) = ct { - Some(ct.ty.walk()) - } else { - None - } + .flat_map(|ct| { + let ty = match ct { + ty::LazyConst::Evaluated(ct) => ct.ty, + ty::LazyConst::Unevaluated(def_id, _) => tcx.type_of(*def_id), + }; + ty.walk() }) - .flatten() .count(); debug!(" => type length={}, const length={}", type_length, const_length); From de4478af91765999f51b2950bea16686ee4cd60a Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 6 Mar 2019 09:58:27 +0000 Subject: [PATCH 34/34] Refactor const_to_op --- src/librustc_mir/interpret/operand.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 1ebff41151011..206eaaf1787c5 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -589,17 +589,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> val: ty::Const<'tcx>, layout: Option>, ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + let val = self.monomorphize(val)?; let layout = from_known_layout(layout, || { - let ty = self.monomorphize(val.ty)?; - self.layout_of(ty) + self.layout_of(val.ty) })?; - let val = match val.val { - ConstValue::Param(_) => self.monomorphize(val)?.val, - ConstValue::Infer(_) => bug!(), - val => val, - }; - let op = match val { - ConstValue::Param(_) | ConstValue::Infer(_) => unreachable!(), + let op = match val.val { + ConstValue::Param(_) | ConstValue::Infer(_) => bug!(), ConstValue::ByRef(ptr, alloc) => { // We rely on mutability being set correctly in that allocation to prevent writes // where none should happen -- and for `static mut`, we copy on demand anyway.