From cc0fbdffe7db21649f45b3407ff9766636727690 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 21 Dec 2019 23:55:34 +0100 Subject: [PATCH 01/48] Automatically prefer integer addresses for zst MPlace --- src/librustc_mir/const_eval/eval_queries.rs | 4 +-- src/librustc_mir/interpret/operand.rs | 30 ++++----------------- src/librustc_mir/interpret/place.rs | 19 ++++++------- src/librustc_mir/interpret/terminator.rs | 2 +- src/librustc_mir/interpret/validity.rs | 11 +++----- src/librustc_mir/interpret/visitor.rs | 10 ++----- src/librustc_mir/transform/const_prop.rs | 3 ++- 7 files changed, 26 insertions(+), 53 deletions(-) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index dbeb75b60c290..8c41f7d1e61f6 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -115,7 +115,7 @@ pub(super) fn op_to_const<'tcx>( // by-val is if we are in const_field, i.e., if this is (a field of) something that we // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or // structs containing such. - op.try_as_mplace() + op.try_as_mplace(ecx) }; let val = match immediate { Ok(mplace) => { @@ -132,7 +132,7 @@ pub(super) fn op_to_const<'tcx>( // `Immediate` is when we are called from `const_field`, and that `Immediate` // comes from a constant so it can happen have `Undef`, because the indirect // memory that was read had undefined bytes. - let mplace = op.assert_mem_place(); + let mplace = op.assert_mem_place(ecx); let ptr = mplace.ptr.assert_ptr(); let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); ConstValue::ByRef { alloc, offset: ptr.offset } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index def979b63b52a..00aecf74c7d3d 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -267,7 +267,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, op: OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - match op.try_as_mplace() { + match op.try_as_mplace(self) { Ok(mplace) => Ok(self.force_mplace_ptr(mplace)?.into()), Err(imm) => Ok(imm.into()), // Nothing to cast/force } @@ -335,7 +335,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, src: OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, Result, MPlaceTy<'tcx, M::PointerTag>>> { - Ok(match src.try_as_mplace() { + Ok(match src.try_as_mplace(self) { Ok(mplace) => { if let Some(val) = self.try_read_immediate_from_mplace(mplace)? { Ok(val) @@ -383,7 +383,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { op: OpTy<'tcx, M::PointerTag>, field: u64, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - let base = match op.try_as_mplace() { + let base = match op.try_as_mplace(self) { Ok(mplace) => { // The easy case let field = self.mplace_field(mplace, field)?; @@ -420,7 +420,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { variant: VariantIdx, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // Downcasts only change the layout - Ok(match op.try_as_mplace() { + Ok(match op.try_as_mplace(self) { Ok(mplace) => self.mplace_downcast(mplace, variant)?.into(), Err(..) => { let layout = op.layout.for_variant(self, variant); @@ -439,30 +439,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Field(field, _) => self.operand_field(base, field.index() as u64)?, Downcast(_, variant) => self.operand_downcast(base, variant)?, Deref => self.deref_operand(base)?.into(), - ConstantIndex { .. } | Index(_) if base.layout.is_zst() => { - OpTy { - op: Operand::Immediate(Scalar::zst().into()), - // the actual index doesn't matter, so we just pick a convenient one like 0 - layout: base.layout.field(self, 0)?, - } - } - Subslice { from, to, from_end } if base.layout.is_zst() => { - let elem_ty = if let ty::Array(elem_ty, _) = base.layout.ty.kind { - elem_ty - } else { - bug!("slices shouldn't be zero-sized"); - }; - assert!(!from_end, "arrays shouldn't be subsliced from the end"); - - OpTy { - op: Operand::Immediate(Scalar::zst().into()), - layout: self.layout_of(self.tcx.mk_array(elem_ty, (to - from) as u64))?, - } - } Subslice { .. } | ConstantIndex { .. } | Index(_) => { // The rest should only occur as mplace, we do not use Immediates for types // allowing such operations. This matches place_projection forcing an allocation. - let mplace = base.assert_mem_place(); + let mplace = base.assert_mem_place(self); self.mplace_projection(mplace, proj_elem)?.into() } }) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index f4ac7de852af0..7fbe691f183cc 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -200,16 +200,17 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { // These are defined here because they produce a place. impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { #[inline(always)] - pub fn try_as_mplace(self) -> Result, ImmTy<'tcx, Tag>> { + pub fn try_as_mplace(self, cx: &impl HasDataLayout) -> Result, ImmTy<'tcx, Tag>> { match *self { Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }), + Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout, cx)), Operand::Immediate(imm) => Err(ImmTy { imm, layout: self.layout }), } } #[inline(always)] - pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> { - self.try_as_mplace().unwrap() + pub fn assert_mem_place(self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> { + self.try_as_mplace(cx).unwrap() } } @@ -305,7 +306,7 @@ where /// On success, returns `None` for zero-sized accesses (where nothing else is /// left to do) and a `Pointer` to use for the actual access otherwise. #[inline] - pub fn check_mplace_access( + pub(super) fn check_mplace_access( &self, place: MPlaceTy<'tcx, M::PointerTag>, size: Option, @@ -338,7 +339,7 @@ where /// Force `place.ptr` to a `Pointer`. /// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot. - pub fn force_mplace_ptr( + pub(super) fn force_mplace_ptr( &self, mut place: MPlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { @@ -415,7 +416,7 @@ where // Iterates over all fields of an array. Much more efficient than doing the // same by repeatedly calling `mplace_array`. - pub fn mplace_array_fields( + pub(super) fn mplace_array_fields( &self, base: MPlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx, impl Iterator>> + 'tcx> @@ -430,7 +431,7 @@ where Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl))) } - pub fn mplace_subslice( + fn mplace_subslice( &self, base: MPlaceTy<'tcx, M::PointerTag>, from: u64, @@ -471,7 +472,7 @@ where base.offset(from_offset, meta, layout, self) } - pub fn mplace_downcast( + pub(super) fn mplace_downcast( &self, base: MPlaceTy<'tcx, M::PointerTag>, variant: VariantIdx, @@ -482,7 +483,7 @@ where } /// Project into an mplace - pub fn mplace_projection( + pub(super) fn mplace_projection( &self, base: MPlaceTy<'tcx, M::PointerTag>, proj_elem: &mir::PlaceElem<'tcx>, diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index a28bb539fd070..37dcab512b991 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -378,7 +378,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } None => { // Unsized self. - args[0].assert_mem_place() + args[0].assert_mem_place(self) } }; // Find and consult vtable diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 7b82bed2e7a61..73f479ede769d 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -571,12 +571,9 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ) -> InterpResult<'tcx> { match op.layout.ty.kind { ty::Str => { - let mplace = op.assert_mem_place(); // strings are never immediate - try_validation!( - self.ecx.read_str(mplace), - "uninitialized or non-UTF-8 data in str", - self.path - ); + let mplace = op.assert_mem_place(self.ecx); // strings are never immediate + try_validation!(self.ecx.read_str(mplace), + "uninitialized or non-UTF-8 data in str", self.path); } ty::Array(tys, ..) | ty::Slice(tys) if { @@ -604,7 +601,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> return Ok(()); } // non-ZST array cannot be immediate, slices are never immediate - let mplace = op.assert_mem_place(); + let mplace = op.assert_mem_place(self.ecx); // This is the length of the array/slice. let len = mplace.len(self.ecx)?; // zero length slices have nothing to be checked diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 2cfcf0ff06d0f..d2594e8707104 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -223,7 +223,7 @@ macro_rules! make_value_visitor { match v.layout().ty.kind { ty::Dynamic(..) => { // immediate trait objects are not a thing - let dest = v.to_op(self.ecx())?.assert_mem_place(); + let dest = v.to_op(self.ecx())?.assert_mem_place(self.ecx()); let inner = self.ecx().unpack_dyn_trait(dest)?.1; trace!("walk_value: dyn object layout: {:#?}", inner.layout); // recurse with the inner type @@ -292,13 +292,7 @@ macro_rules! make_value_visitor { }, layout::FieldPlacement::Array { .. } => { // Let's get an mplace first. - let mplace = if v.layout().is_zst() { - // it's a ZST, the memory content cannot matter - MPlaceTy::dangling(v.layout(), self.ecx()) - } else { - // non-ZST array/slice/str cannot be immediate - v.to_op(self.ecx())?.assert_mem_place() - }; + let mplace = v.to_op(self.ecx())?.assert_mem_place(self.ecx()); // Now we can go over all the fields. let iter = self.ecx().mplace_array_fields(mplace)? .map(|f| f.and_then(|f| { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 6b0f7be86841e..d5d56b36cf4c3 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -707,7 +707,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ScalarMaybeUndef::Scalar(r), )) => l.is_bits() && r.is_bits(), interpret::Operand::Indirect(_) if mir_opt_level >= 2 => { - intern_const_alloc_recursive(&mut self.ecx, None, op.assert_mem_place()) + let mplace = op.assert_mem_place(&self.ecx); + intern_const_alloc_recursive(&mut self.ecx, None, mplace) .expect("failed to intern alloc"); true } From 5b770b080fab5a64875ffb10deff9e6d14950fc0 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 00:33:15 +0100 Subject: [PATCH 02/48] Remove a ZST special casing that is not necessary anymore --- src/librustc_mir/interpret/validity.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 73f479ede769d..786909731531f 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -596,15 +596,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> { // Optimized handling for arrays of integer/float type. - // bailing out for zsts is ok, since the array element type can only be int/float - if op.layout.is_zst() { - return Ok(()); - } - // non-ZST array cannot be immediate, slices are never immediate + // Arrays cannot be immediate, slices are never immediate. let mplace = op.assert_mem_place(self.ecx); // This is the length of the array/slice. let len = mplace.len(self.ecx)?; - // zero length slices have nothing to be checked + // Zero length slices have nothing to be checked. if len == 0 { return Ok(()); } From 4a5c35bc4490ecf5b06d311917ac64be63673d3c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 00:35:56 +0100 Subject: [PATCH 03/48] Fix an ICE happening due code assuming that `MPlaceTy` cannot have integer addresses --- src/librustc_mir/const_eval/eval_queries.rs | 18 ++------------ src/librustc_mir/interpret/place.rs | 26 ++++++++++++++++++--- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 8c41f7d1e61f6..f28517c667265 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -118,25 +118,11 @@ pub(super) fn op_to_const<'tcx>( op.try_as_mplace(ecx) }; let val = match immediate { - Ok(mplace) => { - let ptr = mplace.ptr.assert_ptr(); - let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - ConstValue::ByRef { alloc, offset: ptr.offset } - } + Ok(mplace) => mplace.to_const_value(ecx.tcx.tcx), // see comment on `let try_as_immediate` above Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x { ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s), - ScalarMaybeUndef::Undef => { - // When coming out of "normal CTFE", we'll always have an `Indirect` operand as - // argument and we will not need this. The only way we can already have an - // `Immediate` is when we are called from `const_field`, and that `Immediate` - // comes from a constant so it can happen have `Undef`, because the indirect - // memory that was read had undefined bytes. - let mplace = op.assert_mem_place(ecx); - let ptr = mplace.ptr.assert_ptr(); - let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - ConstValue::ByRef { alloc, offset: ptr.offset } - } + ScalarMaybeUndef::Undef => op.assert_mem_place(ecx).to_const_value(ecx.tcx.tcx), }, Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => { let (data, start) = match a.not_undef().unwrap() { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 7fbe691f183cc..54a692c66e3bc 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -6,12 +6,13 @@ use std::convert::TryFrom; use std::hash::Hash; use rustc::mir; -use rustc::mir::interpret::truncate; +use rustc::mir::interpret::{truncate, ConstValue}; use rustc::ty::layout::{ self, Align, HasDataLayout, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx, }; use rustc::ty::TypeFoldable; use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc_macros::HashStable; use super::{ @@ -195,15 +196,34 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { _ => bug!("vtable not supported on type {:?}", self.layout.ty), } } + + #[inline(always)] + pub fn to_const_value(self, tcx: TyCtxt<'tcx>) -> ConstValue<'tcx> { + match self.mplace.ptr { + Scalar::Ptr(ptr) => { + let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + ConstValue::ByRef { alloc, offset: ptr.offset } + } + Scalar::Raw { data, .. } => { + assert_eq!(data, self.layout.align.abi.bytes().into()); + ConstValue::Scalar(Scalar::zst()) + } + } + } } // These are defined here because they produce a place. impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { #[inline(always)] - pub fn try_as_mplace(self, cx: &impl HasDataLayout) -> Result, ImmTy<'tcx, Tag>> { + pub fn try_as_mplace( + self, + cx: &impl HasDataLayout, + ) -> Result, ImmTy<'tcx, Tag>> { match *self { Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }), - Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout, cx)), + Operand::Immediate(_) if self.layout.is_zst() => { + Ok(MPlaceTy::dangling(self.layout, cx)) + } Operand::Immediate(imm) => Err(ImmTy { imm, layout: self.layout }), } } From cac6f4c12db5fadff650267a8456d5835d19b136 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 26 Dec 2019 23:32:34 +0100 Subject: [PATCH 04/48] Move `to_const_value` from `MPlaceTy` to its only use site --- src/librustc_mir/const_eval/eval_queries.rs | 15 +++++++++++++-- src/librustc_mir/interpret/place.rs | 17 +---------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index f28517c667265..b0add10dcac43 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -117,12 +117,23 @@ pub(super) fn op_to_const<'tcx>( // structs containing such. op.try_as_mplace(ecx) }; + + let to_const_value = |mplace: MPlaceTy<'_>| match mplace.ptr { + Scalar::Ptr(ptr) => { + let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + ConstValue::ByRef { alloc, offset: ptr.offset } + } + Scalar::Raw { data, .. } => { + assert_eq!(data, mplace.layout.align.abi.bytes().into()); + ConstValue::Scalar(Scalar::zst()) + } + }; let val = match immediate { - Ok(mplace) => mplace.to_const_value(ecx.tcx.tcx), + Ok(mplace) => to_const_value(mplace), // see comment on `let try_as_immediate` above Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x { ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s), - ScalarMaybeUndef::Undef => op.assert_mem_place(ecx).to_const_value(ecx.tcx.tcx), + ScalarMaybeUndef::Undef => to_const_value(op.assert_mem_place(ecx)), }, Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => { let (data, start) = match a.not_undef().unwrap() { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 54a692c66e3bc..c8499d845dd13 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -6,13 +6,12 @@ use std::convert::TryFrom; use std::hash::Hash; use rustc::mir; -use rustc::mir::interpret::{truncate, ConstValue}; +use rustc::mir::interpret::truncate; use rustc::ty::layout::{ self, Align, HasDataLayout, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx, }; use rustc::ty::TypeFoldable; use rustc::ty::{self, Ty}; -use rustc::ty::{self, Ty, TyCtxt}; use rustc_macros::HashStable; use super::{ @@ -196,20 +195,6 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { _ => bug!("vtable not supported on type {:?}", self.layout.ty), } } - - #[inline(always)] - pub fn to_const_value(self, tcx: TyCtxt<'tcx>) -> ConstValue<'tcx> { - match self.mplace.ptr { - Scalar::Ptr(ptr) => { - let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - ConstValue::ByRef { alloc, offset: ptr.offset } - } - Scalar::Raw { data, .. } => { - assert_eq!(data, self.layout.align.abi.bytes().into()); - ConstValue::Scalar(Scalar::zst()) - } - } - } } // These are defined here because they produce a place. From 4fbe434c5c10d9a0550db4ae93aaac3a0ed9816e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 00:38:10 +0100 Subject: [PATCH 05/48] Poison any `MemPlace` created from a zst Operand (or otherwise via `MPlaceTy::dangling`) so you can't get the address back out. --- src/librustc_mir/interpret/eval_context.rs | 13 ++- src/librustc_mir/interpret/intern.rs | 5 +- src/librustc_mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/place.rs | 98 ++++++++++++++++------ src/librustc_mir/interpret/snapshot.rs | 12 ++- src/librustc_mir/interpret/validity.rs | 15 ++-- 6 files changed, 102 insertions(+), 43 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 551e3e837c988..c5c2a6769e44a 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -20,7 +20,7 @@ use rustc_macros::HashStable; use rustc_span::source_map::{self, Span, DUMMY_SP}; use super::{ - Immediate, MPlaceTy, Machine, MemPlace, Memory, OpTy, Operand, Place, PlaceTy, + Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy, ScalarMaybeUndef, StackPopInfo, }; @@ -393,7 +393,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// This can fail to provide an answer for extern types. pub(super) fn size_and_align_of( &self, - metadata: Option>, + metadata: MemPlaceMeta, layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { if !layout.is_unsized() { @@ -465,14 +465,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(Some((size, align))) } ty::Dynamic(..) => { - let vtable = metadata.expect("dyn trait fat ptr must have vtable"); + let vtable = metadata.unwrap_unsized(); // Read size and align from vtable (already checks size). Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) } ty::Slice(_) | ty::Str => { - let len = - metadata.expect("slice fat ptr must have length").to_machine_usize(self)?; + let len = metadata.unwrap_unsized().to_machine_usize(self)?; let elem = layout.field(self, 0)?; // Make sure the slice is not too big. @@ -818,8 +817,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { " by align({}){} ref:", mplace.align.bytes(), match mplace.meta { - Some(meta) => format!(" meta({:?})", meta), - None => String::new(), + MemPlaceMeta::Unsized(meta) => format!(" meta({:?})", meta), + MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(), } ) .unwrap(); diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 7c6129ef30ffd..56e489d0bd590 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -193,7 +193,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx { // Validation has already errored on an invalid vtable pointer so we can safely not // do anything if this is not a real pointer. - if let Scalar::Ptr(vtable) = mplace.meta.unwrap() { + if let Scalar::Ptr(vtable) = mplace.meta.unwrap_unsized() { // Explicitly choose `Immutable` here, since vtables are immutable, even // if the reference of the fat pointer is mutable. self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; @@ -226,7 +226,8 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx | (InternMode::Const, hir::Mutability::Mut) => match referenced_ty.kind { ty::Array(_, n) if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {} - ty::Slice(_) if mplace.meta.unwrap().to_machine_usize(self.ecx)? == 0 => {} + ty::Slice(_) + if mplace.meta.unwrap_unsized().to_machine_usize(self.ecx)? == 0 => {} _ => bug!("const qualif failed to prevent mutable references"), }, } diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 0d35eae6ed08d..2e8fbb95ca2e5 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -20,7 +20,7 @@ pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one pla pub use self::eval_context::{Frame, InterpCx, LocalState, LocalValue, StackPopCleanup}; -pub use self::place::{MPlaceTy, MemPlace, Place, PlaceTy}; +pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind}; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index c8499d845dd13..6d848092defe5 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -20,6 +20,45 @@ use super::{ RawConst, Scalar, ScalarMaybeUndef, }; +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] +pub enum MemPlaceMeta { + Unsized(Scalar), + /// `Sized` types or unsized `extern type` + None, + /// The address of this place may not be taken. This protects the `MemPlace` from coming from + /// a ZST Operand with a backing allocation and being converted to an integer address. This + /// should be impossible, because you can't take the address of an operand, but this is a second + /// protection layer ensuring that we don't mess up. + Poison, +} + +impl MemPlaceMeta { + pub fn unwrap_unsized(self) -> Scalar { + match self { + Self::Unsized(s) => s, + Self::None | Self::Poison => { + bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)") + } + } + } + fn is_unsized(self) -> bool { + match self { + Self::Unsized(_) => true, + Self::None | Self::Poison => false, + } + } +} + +impl MemPlaceMeta { + pub fn erase_tag(self) -> MemPlaceMeta<()> { + match self { + Self::Unsized(s) => MemPlaceMeta::Unsized(s.erase_tag()), + Self::None => MemPlaceMeta::None, + Self::Poison => MemPlaceMeta::Poison, + } + } +} + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] pub struct MemPlace { /// A place may have an integral pointer for ZSTs, and since it might @@ -30,7 +69,7 @@ pub struct MemPlace { /// Metadata for unsized places. Interpretation is up to the type. /// Must not be present for sized types, but can be missing for unsized types /// (e.g., `extern type`). - pub meta: Option>, + pub meta: MemPlaceMeta, } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] @@ -88,16 +127,12 @@ impl MemPlace { #[inline] pub fn erase_tag(self) -> MemPlace { - MemPlace { - ptr: self.ptr.erase_tag(), - align: self.align, - meta: self.meta.map(Scalar::erase_tag), - } + MemPlace { ptr: self.ptr.erase_tag(), align: self.align, meta: self.meta.erase_tag() } } #[inline(always)] pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self { - MemPlace { ptr, align, meta: None } + MemPlace { ptr, align, meta: MemPlaceMeta::None } } /// Produces a Place that will error if attempted to be read from or written to @@ -116,15 +151,19 @@ impl MemPlace { #[inline(always)] pub fn to_ref(self) -> Immediate { match self.meta { - None => Immediate::Scalar(self.ptr.into()), - Some(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()), + MemPlaceMeta::None => Immediate::Scalar(self.ptr.into()), + MemPlaceMeta::Unsized(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()), + MemPlaceMeta::Poison => bug!( + "MPlaceTy::dangling may never be used to produce a \ + place that will have the address of its pointee taken" + ), } } pub fn offset( self, offset: Size, - meta: Option>, + meta: MemPlaceMeta, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { Ok(MemPlace { @@ -158,7 +197,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { pub fn offset( self, offset: Size, - meta: Option>, + meta: MemPlaceMeta, layout: TyLayout<'tcx>, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { @@ -175,7 +214,9 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { if self.layout.is_unsized() { // We need to consult `meta` metadata match self.layout.ty.kind { - ty::Slice(..) | ty::Str => return self.mplace.meta.unwrap().to_machine_usize(cx), + ty::Slice(..) | ty::Str => { + return self.mplace.meta.unwrap_unsized().to_machine_usize(cx); + } _ => bug!("len not supported on unsized type {:?}", self.layout.ty), } } else { @@ -191,7 +232,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { #[inline] pub(super) fn vtable(self) -> Scalar { match self.layout.ty.kind { - ty::Dynamic(..) => self.mplace.meta.unwrap(), + ty::Dynamic(..) => self.mplace.meta.unwrap_unsized(), _ => bug!("vtable not supported on type {:?}", self.layout.ty), } } @@ -276,8 +317,10 @@ where val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; let layout = self.layout_of(pointee_type)?; let (ptr, meta) = match *val { - Immediate::Scalar(ptr) => (ptr.not_undef()?, None), - Immediate::ScalarPair(ptr, meta) => (ptr.not_undef()?, Some(meta.not_undef()?)), + Immediate::Scalar(ptr) => (ptr.not_undef()?, MemPlaceMeta::None), + Immediate::ScalarPair(ptr, meta) => { + (ptr.not_undef()?, MemPlaceMeta::Unsized(meta.not_undef()?)) + } }; let mplace = MemPlace { @@ -318,7 +361,7 @@ where ) -> InterpResult<'tcx, Option>> { let size = size.unwrap_or_else(|| { assert!(!place.layout.is_unsized()); - assert!(place.meta.is_none()); + assert!(!place.meta.is_unsized()); place.layout.size }); self.memory.check_ptr_access(place.ptr, size, place.align) @@ -411,7 +454,7 @@ where } else { // base.meta could be present; we might be accessing a sized field of an unsized // struct. - (None, offset) + (MemPlaceMeta::None, offset) }; // We do not look at `base.layout.align` nor `field_layout.align`, unlike @@ -433,7 +476,7 @@ where }; let layout = base.layout.field(self, 0)?; let dl = &self.tcx.data_layout; - Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl))) + Ok((0..len).map(move |i| base.offset(i * stride, MemPlaceMeta::None, layout, dl))) } fn mplace_subslice( @@ -466,10 +509,10 @@ where let (meta, ty) = match base.layout.ty.kind { // It is not nice to match on the type, but that seems to be the only way to // implement this. - ty::Array(inner, _) => (None, self.tcx.mk_array(inner, inner_len)), + ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)), ty::Slice(..) => { let len = Scalar::from_uint(inner_len, self.pointer_size()); - (Some(len), base.layout.ty) + (MemPlaceMeta::Unsized(len), base.layout.ty) } _ => bug!("cannot subslice non-array type: `{:?}`", base.layout.ty), }; @@ -483,7 +526,7 @@ where variant: VariantIdx, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // Downcasts only change the layout - assert!(base.meta.is_none()); + assert!(!base.meta.is_unsized()); Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base }) } @@ -977,7 +1020,7 @@ where pub fn force_allocation_maybe_sized( &mut self, place: PlaceTy<'tcx, M::PointerTag>, - meta: Option>, + meta: MemPlaceMeta, ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option)> { let (mplace, size) = match place.place { Place::Local { frame, local } => { @@ -1022,7 +1065,7 @@ where &mut self, place: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - Ok(self.force_allocation_maybe_sized(place, None)?.0) + Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0) } pub fn allocate( @@ -1042,8 +1085,11 @@ where ) -> MPlaceTy<'tcx, M::PointerTag> { let ptr = self.memory.allocate_static_bytes(str.as_bytes(), kind); let meta = Scalar::from_uint(str.len() as u128, self.pointer_size()); - let mplace = - MemPlace { ptr: ptr.into(), align: Align::from_bytes(1).unwrap(), meta: Some(meta) }; + let mplace = MemPlace { + ptr: ptr.into(), + align: Align::from_bytes(1).unwrap(), + meta: MemPlaceMeta::Unsized(meta), + }; let layout = self.layout_of(self.tcx.mk_static_str()).unwrap(); MPlaceTy { mplace, layout } @@ -1151,7 +1197,7 @@ where assert_eq!(align, layout.align.abi); } - let mplace = MPlaceTy { mplace: MemPlace { meta: None, ..*mplace }, layout }; + let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..*mplace }, layout }; Ok((instance, mplace)) } } diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 6790baf31ccb2..120baaf3be68a 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -23,7 +23,9 @@ use rustc_span::source_map::Span; use syntax::ast::Mutability; use super::eval_context::{LocalState, StackPopCleanup}; -use super::{Frame, Immediate, LocalValue, MemPlace, Memory, Operand, Place, ScalarMaybeUndef}; +use super::{ + Frame, Immediate, LocalValue, MemPlace, MemPlaceMeta, Memory, Operand, Place, ScalarMaybeUndef, +}; use crate::const_eval::CompileTimeInterpreter; #[derive(Default)] @@ -205,6 +207,14 @@ impl_snapshot_for!( } ); +impl_snapshot_for!( + enum MemPlaceMeta { + Unsized(s), + None, + Poison, + } +); + impl_snapshot_for!(struct MemPlace { ptr, meta, diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 786909731531f..7a7f431402075 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -16,7 +16,7 @@ use rustc_span::symbol::{sym, Symbol}; use std::hash::Hash; use super::{ - CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Scalar, + CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, ValueVisitor, }; @@ -246,13 +246,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M fn check_wide_ptr_meta( &mut self, - meta: Option>, + meta: MemPlaceMeta, pointee: TyLayout<'tcx>, ) -> InterpResult<'tcx> { let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); match tail.kind { ty::Dynamic(..) => { - let vtable = meta.unwrap(); + let vtable = meta.unwrap_unsized(); try_validation!( self.ecx.memory.check_ptr_access( vtable, @@ -276,7 +276,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M } ty::Slice(..) | ty::Str => { let _len = try_validation!( - meta.unwrap().to_machine_usize(self.ecx), + meta.unwrap_unsized().to_machine_usize(self.ecx), "non-integer slice length in wide pointer", self.path ); @@ -572,8 +572,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> match op.layout.ty.kind { ty::Str => { let mplace = op.assert_mem_place(self.ecx); // strings are never immediate - try_validation!(self.ecx.read_str(mplace), - "uninitialized or non-UTF-8 data in str", self.path); + try_validation!( + self.ecx.read_str(mplace), + "uninitialized or non-UTF-8 data in str", + self.path + ); } ty::Array(tys, ..) | ty::Slice(tys) if { From 23b0c470244e612206486bb51f687ef4f6b6e117 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 00:52:12 +0100 Subject: [PATCH 06/48] Ensure we don't accidentally turn non-zsts into zsts --- src/librustc_mir/const_eval/eval_queries.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index b0add10dcac43..9fbb6e1a39d90 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -125,6 +125,7 @@ pub(super) fn op_to_const<'tcx>( } Scalar::Raw { data, .. } => { assert_eq!(data, mplace.layout.align.abi.bytes().into()); + assert!(mplace.layout.is_zst()); ConstValue::Scalar(Scalar::zst()) } }; From a1990db7c68ead195d1ddf4b245e3c0e6f721fbc Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 00:58:48 +0100 Subject: [PATCH 07/48] Remove a bunch of dead functions and make some functions private --- src/librustc_mir/interpret/operand.rs | 24 ------------------------ src/librustc_mir/interpret/place.rs | 16 +++------------- 2 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 00aecf74c7d3d..ddd9776e89383 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -153,30 +153,6 @@ pub enum Operand { Indirect(MemPlace), } -impl Operand { - #[inline] - pub fn assert_mem_place(self) -> MemPlace - where - Tag: ::std::fmt::Debug, - { - match self { - Operand::Indirect(mplace) => mplace, - _ => bug!("assert_mem_place: expected Operand::Indirect, got {:?}", self), - } - } - - #[inline] - pub fn assert_immediate(self) -> Immediate - where - Tag: ::std::fmt::Debug, - { - match self { - Operand::Immediate(imm) => imm, - _ => bug!("assert_immediate: expected Operand::Immediate, got {:?}", self), - } - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct OpTy<'tcx, Tag = ()> { op: Operand, // Keep this private; it helps enforce invariants. diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 6d848092defe5..f5e8d052b21f1 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -131,13 +131,13 @@ impl MemPlace { } #[inline(always)] - pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self { + fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self { MemPlace { ptr, align, meta: MemPlaceMeta::None } } /// Produces a Place that will error if attempted to be read from or written to #[inline(always)] - pub fn null(cx: &impl HasDataLayout) -> Self { + fn null(cx: &impl HasDataLayout) -> Self { Self::from_scalar_ptr(Scalar::ptr_null(cx), Align::from_bytes(1).unwrap()) } @@ -263,20 +263,10 @@ impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { impl Place { /// Produces a Place that will error if attempted to be read from or written to #[inline(always)] - pub fn null(cx: &impl HasDataLayout) -> Self { + fn null(cx: &impl HasDataLayout) -> Self { Place::Ptr(MemPlace::null(cx)) } - #[inline(always)] - pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self { - Place::Ptr(MemPlace::from_scalar_ptr(ptr, align)) - } - - #[inline(always)] - pub fn from_ptr(ptr: Pointer, align: Align) -> Self { - Place::Ptr(MemPlace::from_ptr(ptr, align)) - } - #[inline] pub fn assert_mem_place(self) -> MemPlace { match self { From f7f59522b6354d66cf1f08ff0b665d3699acd98c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 01:00:05 +0100 Subject: [PATCH 08/48] Add warning label to `try_as_mplace` --- src/librustc_mir/interpret/place.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index f5e8d052b21f1..1f7db45ccff56 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -241,6 +241,8 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { // These are defined here because they produce a place. impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { #[inline(always)] + /// Note: do not call `as_ref` on the resulting place. This function should only be used to + /// read from the resulting mplace, not to get its address back. pub fn try_as_mplace( self, cx: &impl HasDataLayout, @@ -255,6 +257,8 @@ impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { } #[inline(always)] + /// Note: do not call `as_ref` on the resulting place. This function should only be used to + /// read from the resulting mplace, not to get its address back. pub fn assert_mem_place(self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> { self.try_as_mplace(cx).unwrap() } From 29c372bf8b612dd9e23eb2503a1f1167e2f2f47c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 7 Jan 2020 15:51:43 +0100 Subject: [PATCH 09/48] Add more documentation --- src/librustc_mir/const_eval/eval_queries.rs | 7 ++++++- src/librustc_mir/interpret/place.rs | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 9fbb6e1a39d90..d2a0798249ad9 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -124,7 +124,12 @@ pub(super) fn op_to_const<'tcx>( ConstValue::ByRef { alloc, offset: ptr.offset } } Scalar::Raw { data, .. } => { - assert_eq!(data, mplace.layout.align.abi.bytes().into()); + assert_eq!( + data, + mplace.layout.align.abi.bytes().into(), + "this MPlaceTy must come from `try_as_mplace` being used on a zst, so we know what + value this integer address must have", + ); assert!(mplace.layout.is_zst()); ConstValue::Scalar(Scalar::zst()) } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 1f7db45ccff56..69563c5a08de1 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -21,7 +21,9 @@ use super::{ }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] +/// Information required for the sound usage of a `MemPlace`. pub enum MemPlaceMeta { + /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). Unsized(Scalar), /// `Sized` types or unsized `extern type` None, From d0b24e5ee292cc785401c880f21b690f5f3fa1d6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 7 Jan 2020 15:59:14 +0100 Subject: [PATCH 10/48] Actually use the poison value --- src/librustc_mir/interpret/place.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 69563c5a08de1..6428caa8fb0ed 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -180,13 +180,9 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { /// Produces a MemPlace that works for ZST but nothing else #[inline] pub fn dangling(layout: TyLayout<'tcx>, cx: &impl HasDataLayout) -> Self { - MPlaceTy { - mplace: MemPlace::from_scalar_ptr( - Scalar::from_uint(layout.align.abi.bytes(), cx.pointer_size()), - layout.align.abi, - ), - layout, - } + let align = layout.align.abi; + let ptr = Scalar::from_uint(align.bytes(), cx.pointer_size()); + MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout } } /// Replace ptr tag, maintain vtable tag (if any) From 9c0000cacac904a9b04c64ca349f54169b98f60a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 15 Nov 2019 18:53:17 -0800 Subject: [PATCH 11/48] Point at opaque and closure type definitions in type errors --- src/librustc/infer/error_reporting/mod.rs | 97 ++++++++++++++++++- src/librustc_typeck/check/mod.rs | 3 +- .../dont-suggest-missing-await.stderr | 3 + .../suggest-missing-await-closure.stderr | 3 + .../async-await/suggest-missing-await.stderr | 3 + .../ui/closures/closure-reform-bad.stderr | 2 + src/test/ui/impl-trait/equality2.stderr | 12 +++ src/test/ui/issues/issue-24036.stderr | 2 + .../fn-or-tuple-struct-without-args.stderr | 2 +- .../ui/suggestions/opaque-type-error.stderr | 3 + ..._type_does_not_live_long_enough.nll.stderr | 3 + ...eric_type_does_not_live_long_enough.stderr | 3 + .../never_reveal_concrete_type.stderr | 3 + ...o_revealing_outside_defining_module.stderr | 6 ++ 14 files changed, 137 insertions(+), 8 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 92292b3d35f24..e134a6c17cc3d 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -68,9 +68,11 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::Node; -use errors::{struct_span_err, Applicability, DiagnosticBuilder, DiagnosticStyledString}; +use errors::{ + pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticStyledString, +}; use rustc_error_codes::*; -use rustc_span::{Pos, Span}; +use rustc_span::{DesugaringKind, Pos, Span}; use rustc_target::spec::abi; use std::{cmp, fmt}; @@ -1289,6 +1291,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { mut values: Option>, terr: &TypeError<'tcx>, ) { + let span = cause.span(self.tcx); + // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. match terr { @@ -1298,6 +1302,85 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => {} } + struct OpaqueTypesVisitor<'tcx> { + types: FxHashMap<&'static str, FxHashSet>, + expected: FxHashMap<&'static str, FxHashSet>, + found: FxHashMap<&'static str, FxHashSet>, + ignore_span: Span, + tcx: TyCtxt<'tcx>, + } + + impl<'tcx> OpaqueTypesVisitor<'tcx> { + fn visit_expected_found( + tcx: TyCtxt<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ignore_span: Span, + ) -> Self { + let mut types_visitor = OpaqueTypesVisitor { + types: Default::default(), + expected: Default::default(), + found: Default::default(), + ignore_span, + tcx, + }; + expected.visit_with(&mut types_visitor); + std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types); + found.visit_with(&mut types_visitor); + std::mem::swap(&mut types_visitor.found, &mut types_visitor.types); + types_visitor + } + + fn report(&self, err: &mut DiagnosticBuilder<'_>) { + for (target, types) in &[("expected", &self.expected), ("found", &self.found)] { + for (key, values) in types.iter() { + let count = values.len(); + for sp in values { + err.span_label( + *sp, + format!( + "{}this is {}the {} {}{}", + if sp.is_desugaring(DesugaringKind::Async) { + "in the desugared `async fn`, " + } else { + "" + }, + if count > 1 { "one of" } else { "" }, + target, + key, + pluralize!(count), + ), + ); + } + } + } + } + } + + impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + let kind = match t.kind { + ty::Closure(..) => "closure", + ty::Opaque(..) => "opaque type", + _ => "", + }; + match t.kind { + ty::Closure(def_id, _) | ty::Opaque(def_id, _) => { + let span = self.tcx.def_span(def_id); + debug!("note_type_err visit_ty {:?}", span.macro_backtrace()); + if !self.ignore_span.overlaps(span) + && !self.expected.values().any(|exp| exp.iter().any(|sp| *sp == span)) + { + let entry = self.types.entry(kind).or_default(); + entry.insert(span); + } + } + _ => {} + } + t.super_visit_with(self) + } + } + debug!("note_type_err(diag={:?})", diag); let (expected_found, exp_found, is_simple_error) = match values { None => (None, None, false), @@ -1306,6 +1389,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ValuePairs::Types(exp_found) => { let is_simple_err = exp_found.expected.is_simple_text() && exp_found.found.is_simple_text(); + OpaqueTypesVisitor::visit_expected_found( + self.tcx, + exp_found.expected, + exp_found.found, + span, + ) + .report(diag); (is_simple_err, Some(exp_found)) } @@ -1323,8 +1413,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } }; - let span = cause.span(self.tcx); - // Ignore msg for object safe coercion // since E0038 message will be printed match terr { @@ -1336,7 +1424,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } }; - if let Some((expected, found)) = expected_found { let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string()); let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string()); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e6fbae09ba1a0..00ad00cf1b24c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4743,14 +4743,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .join(", "); } Some(Node::Expr(hir::Expr { - kind: ExprKind::Closure(_, _, body_id, closure_span, _), + kind: ExprKind::Closure(_, _, body_id, _, _), span: full_closure_span, .. })) => { if *full_closure_span == expr.span { return false; } - err.span_label(*closure_span, "closure defined here"); msg = "call this closure"; let body = hir.body(*body_id); sugg_call = body diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr index 239f801c39d4e..5bf10e0089207 100644 --- a/src/test/ui/async-await/dont-suggest-missing-await.stderr +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -1,6 +1,9 @@ error[E0308]: mismatched types --> $DIR/dont-suggest-missing-await.rs:14:18 | +LL | async fn make_u32() -> u32 { + | --- in the desugared `async fn`, this is the found opaque type +... LL | take_u32(x) | ^ expected `u32`, found opaque type | diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr index 1efc20082a08a..43366e6bbbfab 100644 --- a/src/test/ui/async-await/suggest-missing-await-closure.stderr +++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr @@ -1,6 +1,9 @@ error[E0308]: mismatched types --> $DIR/suggest-missing-await-closure.rs:16:18 | +LL | async fn make_u32() -> u32 { + | --- in the desugared `async fn`, this is the found opaque type +... LL | take_u32(x) | ^ | | diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 7ab024434b2bf..c7fcbdd8138c1 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -1,6 +1,9 @@ error[E0308]: mismatched types --> $DIR/suggest-missing-await.rs:13:14 | +LL | async fn make_u32() -> u32 { + | --- in the desugared `async fn`, this is the found opaque type +... LL | take_u32(x) | ^ | | diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr index 63236cf542464..16727b58e1ff6 100644 --- a/src/test/ui/closures/closure-reform-bad.stderr +++ b/src/test/ui/closures/closure-reform-bad.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/closure-reform-bad.rs:11:15 | +LL | let f = |s: &str| println!("{}{}", s, string); + | ------------------------------------- this is the found closure LL | call_bare(f) | ^ expected fn pointer, found closure | diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr index 312976b72d20e..4e1880f31dc2a 100644 --- a/src/test/ui/impl-trait/equality2.stderr +++ b/src/test/ui/impl-trait/equality2.stderr @@ -1,6 +1,9 @@ error[E0308]: mismatched types --> $DIR/equality2.rs:25:18 | +LL | fn hide(x: T) -> impl Foo { + | -------- this is the found opaque type +... LL | let _: u32 = hide(0_u32); | --- ^^^^^^^^^^^ expected `u32`, found opaque type | | @@ -12,6 +15,9 @@ LL | let _: u32 = hide(0_u32); error[E0308]: mismatched types --> $DIR/equality2.rs:31:18 | +LL | fn hide(x: T) -> impl Foo { + | -------- this is the found opaque type +... LL | let _: i32 = Leak::leak(hide(0_i32)); | --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type | | @@ -25,6 +31,9 @@ LL | let _: i32 = Leak::leak(hide(0_i32)); error[E0308]: mismatched types --> $DIR/equality2.rs:38:10 | +LL | fn hide(x: T) -> impl Foo { + | -------- this is the expected opaque type +... LL | x = (x.1, | ^^^ expected `u32`, found `i32` | @@ -34,6 +43,9 @@ LL | x = (x.1, error[E0308]: mismatched types --> $DIR/equality2.rs:41:10 | +LL | fn hide(x: T) -> impl Foo { + | -------- this is the expected opaque type +... LL | x.0); | ^^^ expected `i32`, found `u32` | diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr index b0e729a59eb22..670bf57067b56 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/issue-24036.rs:3:9 | +LL | let mut x = |c| c + 1; + | --------- this is the expected closure LL | x = |c| c + 1; | ^^^^^^^^^ expected closure, found a different closure | diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr index 2f0a457a79594..5b18c239b6ee3 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -236,7 +236,7 @@ error[E0308]: mismatched types --> $DIR/fn-or-tuple-struct-without-args.rs:46:20 | LL | let closure = || 42; - | -- closure defined here + | ----- this is the found closure LL | let _: usize = closure; | ----- ^^^^^^^ | | | diff --git a/src/test/ui/suggestions/opaque-type-error.stderr b/src/test/ui/suggestions/opaque-type-error.stderr index 1465b9e49ef1a..3a7ea2bcdd2a4 100644 --- a/src/test/ui/suggestions/opaque-type-error.stderr +++ b/src/test/ui/suggestions/opaque-type-error.stderr @@ -1,6 +1,9 @@ error[E0308]: `if` and `else` have incompatible types --> $DIR/opaque-type-error.rs:20:9 | +LL | fn thing_two() -> impl Future> { + | ------------------------------------ this is the found opaque type +... LL | / if true { LL | | thing_one() | | ----------- expected because of this diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr index dc41cbc5fe3f8..182a3c7e81e60 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr @@ -11,6 +11,9 @@ LL | let z: i32 = x; | --- ^ expected `i32`, found opaque type | | | expected due to this +... +LL | type WrongGeneric = impl 'static; + | ------------------------------------ this is the found opaque type | = note: expected type `i32` found opaque type `WrongGeneric::<&{integer}>` diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index 24d23de797690..b061ec3fff8f4 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -11,6 +11,9 @@ LL | let z: i32 = x; | --- ^ expected `i32`, found opaque type | | | expected due to this +... +LL | type WrongGeneric = impl 'static; + | ------------------------------------ this is the found opaque type | = note: expected type `i32` found opaque type `WrongGeneric::<&{integer}>` diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr index 07962e36da1e6..415ac4bbdcba7 100644 --- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr @@ -1,6 +1,9 @@ error[E0308]: mismatched types --> $DIR/never_reveal_concrete_type.rs:13:27 | +LL | type NoReveal = impl std::fmt::Debug; + | ------------------------------------- this is the found opaque type +... LL | let _: &'static str = x; | ------------ ^ expected `&str`, found opaque type | | diff --git a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr index a2081424ab497..3e67dc90dcb5c 100644 --- a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr +++ b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr @@ -1,6 +1,9 @@ error[E0308]: mismatched types --> $DIR/no_revealing_outside_defining_module.rs:15:19 | +LL | pub type Boo = impl ::std::fmt::Debug; + | -------------------------------------- this is the found opaque type +... LL | let _: &str = bomp(); | ---- ^^^^^^ expected `&str`, found opaque type | | @@ -12,6 +15,9 @@ LL | let _: &str = bomp(); error[E0308]: mismatched types --> $DIR/no_revealing_outside_defining_module.rs:19:5 | +LL | pub type Boo = impl ::std::fmt::Debug; + | -------------------------------------- this is the expected opaque type +... LL | fn bomp() -> boo::Boo { | -------- expected `Boo` because of return type LL | "" From c55615155d161c8abb307db0019ab58545cd246b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 15 Dec 2019 14:05:08 -0800 Subject: [PATCH 12/48] review comments --- src/librustc/infer/error_reporting/mod.rs | 40 +++++++++++-------- .../dont-suggest-missing-await.stderr | 2 +- .../suggest-missing-await-closure.stderr | 2 +- .../async-await/suggest-missing-await.stderr | 5 ++- .../ui/closures/closure-reform-bad.stderr | 2 +- .../extern/extern-types-distinct-types.stderr | 5 +++ src/test/ui/impl-trait/equality2.stderr | 14 +++++-- src/test/ui/issues/issue-24036.stderr | 2 +- .../fn-or-tuple-struct-without-args.stderr | 2 +- .../ui/suggestions/opaque-type-error.stderr | 2 +- ..._type_does_not_live_long_enough.nll.stderr | 2 +- ...eric_type_does_not_live_long_enough.stderr | 2 +- .../never_reveal_concrete_type.stderr | 2 +- ...o_revealing_outside_defining_module.stderr | 4 +- 14 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index e134a6c17cc3d..d0243dad700b6 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1339,16 +1339,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label( *sp, format!( - "{}this is {}the {} {}{}", + "{}the {} {}{}{}", + if count > 1 { "one of " } else { "" }, + target, + key, + pluralize!(count), if sp.is_desugaring(DesugaringKind::Async) { - "in the desugared `async fn`, " + " in the `Output` of this `async fn`" } else { "" }, - if count > 1 { "one of" } else { "" }, - target, - key, - pluralize!(count), ), ); } @@ -1364,18 +1364,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::Opaque(..) => "opaque type", _ => "", }; - match t.kind { - ty::Closure(def_id, _) | ty::Opaque(def_id, _) => { - let span = self.tcx.def_span(def_id); - debug!("note_type_err visit_ty {:?}", span.macro_backtrace()); - if !self.ignore_span.overlaps(span) - && !self.expected.values().any(|exp| exp.iter().any(|sp| *sp == span)) - { - let entry = self.types.entry(kind).or_default(); - entry.insert(span); - } + if let ty::Closure(def_id, _) | ty::Opaque(def_id, _) = t.kind { + let span = self.tcx.def_span(def_id); + // Avoid cluttering the output when the "found" and error span overlap: + // + // error[E0308]: mismatched types + // --> $DIR/issue-20862.rs:2:5 + // | + // LL | |y| x + y + // | ^^^^^^^^^ + // | | + // | the found closure + // | expected `()`, found closure + // | + // = note: expected unit type `()` + // found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]` + if !self.ignore_span.overlaps(span) { + self.types.entry(kind).or_default().insert(span); } - _ => {} } t.super_visit_with(self) } diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr index 5bf10e0089207..5c9b1d2c4d71c 100644 --- a/src/test/ui/async-await/dont-suggest-missing-await.stderr +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/dont-suggest-missing-await.rs:14:18 | LL | async fn make_u32() -> u32 { - | --- in the desugared `async fn`, this is the found opaque type + | --- the found opaque type in the `Output` of this `async fn` ... LL | take_u32(x) | ^ expected `u32`, found opaque type diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr index 43366e6bbbfab..5926c8351ff3d 100644 --- a/src/test/ui/async-await/suggest-missing-await-closure.stderr +++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/suggest-missing-await-closure.rs:16:18 | LL | async fn make_u32() -> u32 { - | --- in the desugared `async fn`, this is the found opaque type + | --- the found opaque type in the `Output` of this `async fn` ... LL | take_u32(x) | ^ diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index c7fcbdd8138c1..c0dc32b83fb0b 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/suggest-missing-await.rs:13:14 | LL | async fn make_u32() -> u32 { - | --- in the desugared `async fn`, this is the found opaque type + | --- the found opaque type in the `Output` of this `async fn` ... LL | take_u32(x) | ^ @@ -16,6 +16,9 @@ LL | take_u32(x) error[E0308]: mismatched types --> $DIR/suggest-missing-await.rs:23:5 | +LL | async fn dummy() {} + | - the found opaque type in the `Output` of this `async fn` +... LL | dummy() | ^^^^^^^ expected `()`, found opaque type | diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr index 16727b58e1ff6..3c4ae450764da 100644 --- a/src/test/ui/closures/closure-reform-bad.stderr +++ b/src/test/ui/closures/closure-reform-bad.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/closure-reform-bad.rs:11:15 | LL | let f = |s: &str| println!("{}{}", s, string); - | ------------------------------------- this is the found closure + | ------------------------------------- the found closure LL | call_bare(f) | ^ expected fn pointer, found closure | diff --git a/src/test/ui/extern/extern-types-distinct-types.stderr b/src/test/ui/extern/extern-types-distinct-types.stderr index 2e258d687d385..32b45ee10ad6f 100644 --- a/src/test/ui/extern/extern-types-distinct-types.stderr +++ b/src/test/ui/extern/extern-types-distinct-types.stderr @@ -1,6 +1,11 @@ error[E0308]: mismatched types --> $DIR/extern-types-distinct-types.rs:9:5 | +LL | type A; + | ------- the found foreign type +LL | type B; + | ------- the expected foreign type +... LL | r | ^ expected extern type `B`, found extern type `A` | diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr index 4e1880f31dc2a..b882514f61609 100644 --- a/src/test/ui/impl-trait/equality2.stderr +++ b/src/test/ui/impl-trait/equality2.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/equality2.rs:25:18 | LL | fn hide(x: T) -> impl Foo { - | -------- this is the found opaque type + | -------- the found opaque type ... LL | let _: u32 = hide(0_u32); | --- ^^^^^^^^^^^ expected `u32`, found opaque type @@ -16,7 +16,7 @@ error[E0308]: mismatched types --> $DIR/equality2.rs:31:18 | LL | fn hide(x: T) -> impl Foo { - | -------- this is the found opaque type + | -------- the found opaque type ... LL | let _: i32 = Leak::leak(hide(0_i32)); | --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type @@ -32,7 +32,10 @@ error[E0308]: mismatched types --> $DIR/equality2.rs:38:10 | LL | fn hide(x: T) -> impl Foo { - | -------- this is the expected opaque type + | -------- + | | + | the expected opaque type + | the found opaque type ... LL | x = (x.1, | ^^^ expected `u32`, found `i32` @@ -44,7 +47,10 @@ error[E0308]: mismatched types --> $DIR/equality2.rs:41:10 | LL | fn hide(x: T) -> impl Foo { - | -------- this is the expected opaque type + | -------- + | | + | the expected opaque type + | the found opaque type ... LL | x.0); | ^^^ expected `i32`, found `u32` diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr index 670bf57067b56..036c05fc848cf 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-24036.rs:3:9 | LL | let mut x = |c| c + 1; - | --------- this is the expected closure + | --------- the expected closure LL | x = |c| c + 1; | ^^^^^^^^^ expected closure, found a different closure | diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr index 5b18c239b6ee3..232e54b5d37b2 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -236,7 +236,7 @@ error[E0308]: mismatched types --> $DIR/fn-or-tuple-struct-without-args.rs:46:20 | LL | let closure = || 42; - | ----- this is the found closure + | ----- the found closure LL | let _: usize = closure; | ----- ^^^^^^^ | | | diff --git a/src/test/ui/suggestions/opaque-type-error.stderr b/src/test/ui/suggestions/opaque-type-error.stderr index 3a7ea2bcdd2a4..167d61bdf7c70 100644 --- a/src/test/ui/suggestions/opaque-type-error.stderr +++ b/src/test/ui/suggestions/opaque-type-error.stderr @@ -2,7 +2,7 @@ error[E0308]: `if` and `else` have incompatible types --> $DIR/opaque-type-error.rs:20:9 | LL | fn thing_two() -> impl Future> { - | ------------------------------------ this is the found opaque type + | ------------------------------------ the found opaque type ... LL | / if true { LL | | thing_one() diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr index 182a3c7e81e60..9549074d4bf78 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr @@ -13,7 +13,7 @@ LL | let z: i32 = x; | expected due to this ... LL | type WrongGeneric = impl 'static; - | ------------------------------------ this is the found opaque type + | ------------------------------------ the found opaque type | = note: expected type `i32` found opaque type `WrongGeneric::<&{integer}>` diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index b061ec3fff8f4..5a7f9d74eba5b 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -13,7 +13,7 @@ LL | let z: i32 = x; | expected due to this ... LL | type WrongGeneric = impl 'static; - | ------------------------------------ this is the found opaque type + | ------------------------------------ the found opaque type | = note: expected type `i32` found opaque type `WrongGeneric::<&{integer}>` diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr index 415ac4bbdcba7..70c99c944d654 100644 --- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/never_reveal_concrete_type.rs:13:27 | LL | type NoReveal = impl std::fmt::Debug; - | ------------------------------------- this is the found opaque type + | ------------------------------------- the found opaque type ... LL | let _: &'static str = x; | ------------ ^ expected `&str`, found opaque type diff --git a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr index 3e67dc90dcb5c..375c0bc7fe2ed 100644 --- a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr +++ b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/no_revealing_outside_defining_module.rs:15:19 | LL | pub type Boo = impl ::std::fmt::Debug; - | -------------------------------------- this is the found opaque type + | -------------------------------------- the found opaque type ... LL | let _: &str = bomp(); | ---- ^^^^^^ expected `&str`, found opaque type @@ -16,7 +16,7 @@ error[E0308]: mismatched types --> $DIR/no_revealing_outside_defining_module.rs:19:5 | LL | pub type Boo = impl ::std::fmt::Debug; - | -------------------------------------- this is the expected opaque type + | -------------------------------------- the expected opaque type ... LL | fn bomp() -> boo::Boo { | -------- expected `Boo` because of return type From 0dcdbaec0b49a149316719b32241d8975bd192c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 15 Dec 2019 22:20:30 -0800 Subject: [PATCH 13/48] Point at the def span of trait refs E0277 --- src/librustc/infer/error_reporting/mod.rs | 9 ++++- src/librustc/traits/error_reporting.rs | 34 ++++++++++++++++--- .../ui/async-await/issue-64130-3-other.stderr | 3 ++ src/test/ui/impl-trait/auto-trait-leak.stderr | 3 ++ .../ui/impl-trait/auto-trait-leak2.stderr | 6 ++++ .../ui/kindck/kindck-nonsendable-1.stderr | 4 ++- src/test/ui/no-send-res-ports.stderr | 15 +++++--- src/test/ui/not-clone-closure.stderr | 10 ++++-- 8 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index d0243dad700b6..d736d45a5a485 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -71,6 +71,7 @@ use rustc_hir::Node; use errors::{ pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticStyledString, }; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_error_codes::*; use rustc_span::{DesugaringKind, Pos, Span}; use rustc_target::spec::abi; @@ -1362,9 +1363,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let kind = match t.kind { ty::Closure(..) => "closure", ty::Opaque(..) => "opaque type", + ty::Generator(..) => "generator", + ty::Foreign(..) => "foreign type", _ => "", }; - if let ty::Closure(def_id, _) | ty::Opaque(def_id, _) = t.kind { + if let ty::Closure(def_id, _) + | ty::Opaque(def_id, _) + | ty::Generator(def_id, ..) + | ty::Foreign(def_id) = t.kind + { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: // diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 00251d55706d7..8c2cc412a480b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -446,7 +446,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { flags.push((sym::from_method, Some(method.to_string()))); } } - if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) { + if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) { flags.push((sym::parent_trait, Some(t))); } @@ -665,13 +665,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Gets the parent trait chain start - fn get_parent_trait_ref(&self, code: &ObligationCauseCode<'tcx>) -> Option { + fn get_parent_trait_ref( + &self, + code: &ObligationCauseCode<'tcx>, + ) -> Option<(String, Option)> { match code { &ObligationCauseCode::BuiltinDerivedObligation(ref data) => { let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); match self.get_parent_trait_ref(&data.parent_code) { Some(t) => Some(t), - None => Some(parent_trait_ref.skip_binder().self_ty().to_string()), + None => { + let ty = parent_trait_ref.skip_binder().self_ty(); + let span = if let ty::Closure(def_id, _) + | ty::Opaque(def_id, _) + | ty::Generator(def_id, ..) + | ty::Foreign(def_id) = ty.kind + { + Some(self.tcx.def_span(def_id)) + } else { + None + }; + Some((ty.to_string(), span)) + } } } _ => None, @@ -719,9 +734,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return; } let trait_ref = trait_predicate.to_poly_trait_ref(); - let (post_message, pre_message) = self + let (post_message, pre_message, type_def) = self .get_parent_trait_ref(&obligation.cause.code) - .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t))) + .map(|(t, s)| { + ( + format!(" in `{}`", t), + format!("within `{}`, ", t), + s.map(|s| (format!("within this `{}`", t), s)), + ) + }) .unwrap_or_default(); let OnUnimplementedNote { message, label, note, enclosing_scope } = @@ -795,6 +816,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } else { err.span_label(span, explanation); } + if let Some((msg, span)) = type_def { + err.span_label(span, &msg); + } if let Some(ref s) = note { // If it has a custom `#[rustc_on_unimplemented]` note, let's display it err.note(s.as_str()); diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr index 155c5cc8ea137..d6828172928dd 100644 --- a/src/test/ui/async-await/issue-64130-3-other.stderr +++ b/src/test/ui/async-await/issue-64130-3-other.stderr @@ -3,6 +3,9 @@ error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future:: | LL | fn is_qux(t: T) { } | ------ --- required by this bound in `is_qux` +LL | +LL | async fn bar() { + | - within this `impl std::future::Future` ... LL | is_qux(bar()); | ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo` diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index d11941fee1824..20815e80acb89 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -77,6 +77,9 @@ LL | fn send(_: T) {} ... LL | send(cycle2().clone()); | ^^^^ `std::rc::Rc` cannot be sent between threads safely +... +LL | fn cycle2() -> impl Clone { + | ---------- within this `impl std::clone::Clone` | = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` = note: required because it appears within the type `impl std::clone::Clone` diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr index d163e1dff7ac9..a93b3dbc71b60 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr @@ -1,6 +1,9 @@ error[E0277]: `std::rc::Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:13:5 | +LL | fn before() -> impl Fn(i32) { + | ------------ within this `impl std::ops::Fn<(i32,)>` +... LL | fn send(_: T) {} | ---- ---- required by this bound in `send` ... @@ -19,6 +22,9 @@ LL | fn send(_: T) {} ... LL | send(after()); | ^^^^ `std::rc::Rc>` cannot be sent between threads safely +... +LL | fn after() -> impl Fn(i32) { + | ------------ within this `impl std::ops::Fn<(i32,)>` | = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22 p:std::rc::Rc>]` diff --git a/src/test/ui/kindck/kindck-nonsendable-1.stderr b/src/test/ui/kindck/kindck-nonsendable-1.stderr index 40b67f8fe8cd7..39640e373991f 100644 --- a/src/test/ui/kindck/kindck-nonsendable-1.stderr +++ b/src/test/ui/kindck/kindck-nonsendable-1.stderr @@ -5,7 +5,9 @@ LL | fn bar(_: F) { } | --- ---- required by this bound in `bar` ... LL | bar(move|| foo(x)); - | ^^^ `std::rc::Rc` cannot be sent between threads safely + | ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]` + | | + | `std::rc::Rc` cannot be sent between threads safely | = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]` diff --git a/src/test/ui/no-send-res-ports.stderr b/src/test/ui/no-send-res-ports.stderr index 8cb690a35c874..65946ee8a20cf 100644 --- a/src/test/ui/no-send-res-ports.stderr +++ b/src/test/ui/no-send-res-ports.stderr @@ -1,13 +1,20 @@ error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely --> $DIR/no-send-res-ports.rs:29:5 | -LL | thread::spawn(move|| { - | ^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely +LL | thread::spawn(move|| { + | _____^^^^^^^^^^^^^_- + | | | + | | `std::rc::Rc<()>` cannot be sent between threads safely +LL | | +LL | | let y = x; +LL | | println!("{:?}", y); +LL | | }); + | |_____- within this `[closure@$DIR/no-send-res-ports.rs:29:19: 33:6 x:main::Foo]` | ::: $SRC_DIR/libstd/thread/mod.rs:LL:COL | -LL | F: Send + 'static, - | ---- required by this bound in `std::thread::spawn` +LL | F: Send + 'static, + | ---- required by this bound in `std::thread::spawn` | = help: within `[closure@$DIR/no-send-res-ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` = note: required because it appears within the type `Port<()>` diff --git a/src/test/ui/not-clone-closure.stderr b/src/test/ui/not-clone-closure.stderr index b66391b83b8db..20c7f81cf5ef5 100644 --- a/src/test/ui/not-clone-closure.stderr +++ b/src/test/ui/not-clone-closure.stderr @@ -1,8 +1,14 @@ error[E0277]: the trait bound `S: std::clone::Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` --> $DIR/not-clone-closure.rs:11:23 | -LL | let hello = hello.clone(); - | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S` +LL | let hello = move || { + | _________________- +LL | | println!("Hello {}", a.0); +LL | | }; + | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` +LL | +LL | let hello = hello.clone(); + | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S` | = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` From 542be6fb6c3e3e3eae5aae04ac772aa0ab53b9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 15 Dec 2019 22:48:45 -0800 Subject: [PATCH 14/48] review comment: wording --- src/librustc/infer/error_reporting/mod.rs | 14 ++++++++------ .../async-await/dont-suggest-missing-await.stderr | 2 +- .../suggest-missing-await-closure.stderr | 2 +- .../ui/async-await/suggest-missing-await.stderr | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index d736d45a5a485..8a444b8d45263 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1340,16 +1340,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label( *sp, format!( - "{}the {} {}{}{}", - if count > 1 { "one of " } else { "" }, - target, - key, - pluralize!(count), + "{}{}{} {}{}", if sp.is_desugaring(DesugaringKind::Async) { - " in the `Output` of this `async fn`" + "the `Output` of this `async fn`'s " + } else if count == 1 { + "the " } else { "" }, + if count > 1 { "one of the " } else { "" }, + target, + key, + pluralize!(count), ), ); } diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr index 5c9b1d2c4d71c..dc3a4752fb1f7 100644 --- a/src/test/ui/async-await/dont-suggest-missing-await.stderr +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/dont-suggest-missing-await.rs:14:18 | LL | async fn make_u32() -> u32 { - | --- the found opaque type in the `Output` of this `async fn` + | --- the `Output` of this `async fn`'s found opaque type ... LL | take_u32(x) | ^ expected `u32`, found opaque type diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr index 5926c8351ff3d..2703cec581ddf 100644 --- a/src/test/ui/async-await/suggest-missing-await-closure.stderr +++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/suggest-missing-await-closure.rs:16:18 | LL | async fn make_u32() -> u32 { - | --- the found opaque type in the `Output` of this `async fn` + | --- the `Output` of this `async fn`'s found opaque type ... LL | take_u32(x) | ^ diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index c0dc32b83fb0b..6ac05a87aae80 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/suggest-missing-await.rs:13:14 | LL | async fn make_u32() -> u32 { - | --- the found opaque type in the `Output` of this `async fn` + | --- the `Output` of this `async fn`'s found opaque type ... LL | take_u32(x) | ^ @@ -17,7 +17,7 @@ error[E0308]: mismatched types --> $DIR/suggest-missing-await.rs:23:5 | LL | async fn dummy() {} - | - the found opaque type in the `Output` of this `async fn` + | - the `Output` of this `async fn`'s found opaque type ... LL | dummy() | ^^^^^^^ expected `()`, found opaque type From b522ba02374169372a80d867894818c92e8c534a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 7 Jan 2020 17:31:37 -0800 Subject: [PATCH 15/48] review comments --- src/librustc/infer/error_reporting/mod.rs | 50 +++++++++++++++-------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 8a444b8d45263..bc75e0a75f09d 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1303,10 +1303,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => {} } + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + enum TyKind { + Closure, + Opaque, + Generator, + Foreign, + } + + impl TyKind { + fn descr(&self) -> &'static str { + match self { + Self::Closure => "closure", + Self::Opaque => "opaque type", + Self::Generator => "generator", + Self::Foreign => "foreign type", + } + } + + fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { + match ty.kind { + ty::Closure(def_id, _) => Some((Self::Closure, def_id)), + ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), + ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), + ty::Foreign(def_id) => Some((Self::Foreign, def_id)), + _ => None, + } + } + } + struct OpaqueTypesVisitor<'tcx> { - types: FxHashMap<&'static str, FxHashSet>, - expected: FxHashMap<&'static str, FxHashSet>, - found: FxHashMap<&'static str, FxHashSet>, + types: FxHashMap>, + expected: FxHashMap>, + found: FxHashMap>, ignore_span: Span, tcx: TyCtxt<'tcx>, } @@ -1350,7 +1379,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }, if count > 1 { "one of the " } else { "" }, target, - key, + key.descr(), pluralize!(count), ), ); @@ -1362,18 +1391,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - let kind = match t.kind { - ty::Closure(..) => "closure", - ty::Opaque(..) => "opaque type", - ty::Generator(..) => "generator", - ty::Foreign(..) => "foreign type", - _ => "", - }; - if let ty::Closure(def_id, _) - | ty::Opaque(def_id, _) - | ty::Generator(def_id, ..) - | ty::Foreign(def_id) = t.kind - { + if let Some((kind, def_id)) = TyKind::from_ty(t) { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: // From ffcdbad263fc2522696b3376627aca503fe0fe8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2020 09:09:43 -0800 Subject: [PATCH 16/48] review comments --- src/librustc/infer/error_reporting/mod.rs | 66 ++++++++++++++--------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index bc75e0a75f09d..b6d6ca0dcef72 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1303,15 +1303,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => {} } + /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks + /// extra information about each type, but we only care about the category. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - enum TyKind { + enum TyCategory { Closure, Opaque, Generator, Foreign, } - impl TyKind { + impl TyCategory { fn descr(&self) -> &'static str { match self { Self::Closure => "closure", @@ -1334,8 +1336,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { struct OpaqueTypesVisitor<'tcx> { types: FxHashMap>, - expected: FxHashMap>, - found: FxHashMap>, + expected: FxHashMap>, + found: FxHashMap>, ignore_span: Span, tcx: TyCtxt<'tcx>, } @@ -1354,6 +1356,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ignore_span, tcx, }; + // The visitor puts all the relevant encountered types in `self.types`, but in + // here we want to visit two separate types with no relation to each other, so we + // move the results from `types` to `expected` or `found` as appropriate. expected.visit_with(&mut types_visitor); std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types); found.visit_with(&mut types_visitor); @@ -1362,28 +1367,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fn report(&self, err: &mut DiagnosticBuilder<'_>) { - for (target, types) in &[("expected", &self.expected), ("found", &self.found)] { - for (key, values) in types.iter() { - let count = values.len(); - for sp in values { - err.span_label( - *sp, - format!( - "{}{}{} {}{}", - if sp.is_desugaring(DesugaringKind::Async) { - "the `Output` of this `async fn`'s " - } else if count == 1 { - "the " - } else { - "" - }, - if count > 1 { "one of the " } else { "" }, - target, - key.descr(), - pluralize!(count), - ), - ); - } + self.add_labels_for_types(err, "expected", &self.expected); + self.add_labels_for_types(err, "found", &self.found); + } + + fn add_labels_for_types( + &self, + err: &mut DiagnosticBuilder<'_>, + target: &str, + types: &FxHashMap>, + ) { + for (key, values) in types.iter() { + let count = values.len(); + let kind = key.descr(); + for sp in values { + err.span_label( + *sp, + format!( + "{}{}{} {}{}", + if sp.is_desugaring(DesugaringKind::Async) { + "the `Output` of this `async fn`'s " + } else if count == 1 { + "the " + } else { + "" + }, + if count > 1 { "one of the " } else { "" }, + target, + key, + pluralize!(count), + ), + ); } } } From 705e0874de4787dd65eb8484fd67ad635e136c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2020 09:26:47 -0800 Subject: [PATCH 17/48] reduce code duplication --- src/librustc/infer/error_reporting/mod.rs | 70 +++++++++++------------ src/librustc/traits/error_reporting.rs | 13 +---- 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index b6d6ca0dcef72..27523b1e689e2 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1303,39 +1303,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => {} } - /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks - /// extra information about each type, but we only care about the category. - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - enum TyCategory { - Closure, - Opaque, - Generator, - Foreign, - } - - impl TyCategory { - fn descr(&self) -> &'static str { - match self { - Self::Closure => "closure", - Self::Opaque => "opaque type", - Self::Generator => "generator", - Self::Foreign => "foreign type", - } - } - - fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { - match ty.kind { - ty::Closure(def_id, _) => Some((Self::Closure, def_id)), - ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), - ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), - ty::Foreign(def_id) => Some((Self::Foreign, def_id)), - _ => None, - } - } - } - struct OpaqueTypesVisitor<'tcx> { - types: FxHashMap>, + types: FxHashMap>, expected: FxHashMap>, found: FxHashMap>, ignore_span: Span, @@ -1375,7 +1344,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, err: &mut DiagnosticBuilder<'_>, target: &str, - types: &FxHashMap>, + types: &FxHashMap>, ) { for (key, values) in types.iter() { let count = values.len(); @@ -1394,7 +1363,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }, if count > 1 { "one of the " } else { "" }, target, - key, + kind, pluralize!(count), ), ); @@ -1405,7 +1374,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - if let Some((kind, def_id)) = TyKind::from_ty(t) { + if let Some((kind, def_id)) = TyCategory::from_ty(t) { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: // @@ -2067,3 +2036,34 @@ impl<'tcx> ObligationCause<'tcx> { } } } + +/// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks +/// extra information about each type, but we only care about the category. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +crate enum TyCategory { + Closure, + Opaque, + Generator, + Foreign, +} + +impl TyCategory { + fn descr(&self) -> &'static str { + match self { + Self::Closure => "closure", + Self::Opaque => "opaque type", + Self::Generator => "generator", + Self::Foreign => "foreign type", + } + } + + pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { + match ty.kind { + ty::Closure(def_id, _) => Some((Self::Closure, def_id)), + ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), + ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), + ty::Foreign(def_id) => Some((Self::Foreign, def_id)), + _ => None, + } + } +} diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8c2cc412a480b..a42ddbbbcc6a3 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -6,7 +6,7 @@ use super::{ TraitNotObjectSafe, }; -use crate::infer::error_reporting::TypeAnnotationNeeded as ErrorCode; +use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{self, InferCtxt}; use crate::mir::interpret::ErrorHandled; @@ -676,15 +676,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some(t) => Some(t), None => { let ty = parent_trait_ref.skip_binder().self_ty(); - let span = if let ty::Closure(def_id, _) - | ty::Opaque(def_id, _) - | ty::Generator(def_id, ..) - | ty::Foreign(def_id) = ty.kind - { - Some(self.tcx.def_span(def_id)) - } else { - None - }; + let span = + TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id)); Some((ty.to_string(), span)) } } From 33ae3220b638551834fddf5c0658563d8a52e89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2020 09:28:01 -0800 Subject: [PATCH 18/48] remove unnecessary `Debug` --- src/librustc/infer/error_reporting/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 27523b1e689e2..5e5f39e6c7a22 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -2039,7 +2039,7 @@ impl<'tcx> ObligationCause<'tcx> { /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks /// extra information about each type, but we only care about the category. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] crate enum TyCategory { Closure, Opaque, From bcab59ed8341a585e7cac5475bc2a41e1f96defa Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 6 Jan 2020 05:32:17 +0100 Subject: [PATCH 19/48] lowering: simplify HoFs --- src/librustc_ast_lowering/item.rs | 7 ++-- src/librustc_ast_lowering/lib.rs | 60 +++++++++++++------------------ 2 files changed, 26 insertions(+), 41 deletions(-) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index a5892a22d9dfa..7aef4b11ae3f9 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -26,12 +26,9 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { } impl<'a, 'lowering, 'hir> ItemLowerer<'a, 'lowering, 'hir> { - fn with_trait_impl_ref(&mut self, trait_impl_ref: &Option, f: F) - where - F: FnOnce(&mut Self), - { + fn with_trait_impl_ref(&mut self, impl_ref: &Option, f: impl FnOnce(&mut Self)) { let old = self.lctx.is_in_trait_impl; - self.lctx.is_in_trait_impl = if let &None = trait_impl_ref { false } else { true }; + self.lctx.is_in_trait_impl = if let &None = impl_ref { false } else { true }; f(self); self.lctx.is_in_trait_impl = old; } diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 385153b62ce82..5b68018683c47 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -433,10 +433,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn with_hir_id_owner(&mut self, owner: Option, f: F) -> T - where - F: FnOnce(&mut Self) -> T, - { + fn with_hir_id_owner( + &mut self, + owner: Option, + f: impl FnOnce(&mut Self) -> T, + ) -> T { let old = mem::replace(&mut self.hir_id_owner, owner); let r = f(self); self.hir_id_owner = old; @@ -577,10 +578,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lowered } - fn lower_node_id_generic(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> hir::HirId - where - F: FnOnce(&mut Self) -> hir::HirId, - { + fn lower_node_id_generic( + &mut self, + ast_node_id: NodeId, + alloc_hir_id: impl FnOnce(&mut Self) -> hir::HirId, + ) -> hir::HirId { if ast_node_id == DUMMY_NODE_ID { return hir::DUMMY_HIR_ID; } @@ -604,10 +606,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn with_hir_id_owner(&mut self, owner: NodeId, f: F) -> T - where - F: FnOnce(&mut Self) -> T, - { + fn with_hir_id_owner(&mut self, owner: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { let counter = self .item_local_id_counters .insert(owner, HIR_ID_COUNTER_LOCKED) @@ -736,15 +735,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Presuming that in-band lifetimes are enabled, then /// `self.anonymous_lifetime_mode` will be updated to match the /// parameter while `f` is running (and restored afterwards). - fn collect_in_band_defs( + fn collect_in_band_defs( &mut self, parent_id: DefId, anonymous_lifetime_mode: AnonymousLifetimeMode, - f: F, - ) -> (Vec>, T) - where - F: FnOnce(&mut Self) -> (Vec>, T), - { + f: impl FnOnce(&mut Self) -> (Vec>, T), + ) -> (Vec>, T) { assert!(!self.is_collecting_in_band_lifetimes); assert!(self.lifetimes_to_define.is_empty()); let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode; @@ -847,10 +843,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // This is used to track which lifetimes have already been defined, and // which are new in-band lifetimes that need to have a definition created // for them. - fn with_in_scope_lifetime_defs(&mut self, params: &[GenericParam], f: F) -> T - where - F: FnOnce(&mut Self) -> T, - { + fn with_in_scope_lifetime_defs( + &mut self, + params: &[GenericParam], + f: impl FnOnce(&mut Self) -> T, + ) -> T { let old_len = self.in_scope_lifetimes.len(); let lt_def_names = params.iter().filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => Some(ParamName::Plain(param.ident.modern())), @@ -870,16 +867,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Presuming that in-band lifetimes are enabled, then /// `self.anonymous_lifetime_mode` will be updated to match the /// parameter while `f` is running (and restored afterwards). - fn add_in_band_defs( + fn add_in_band_defs( &mut self, generics: &Generics, parent_id: DefId, anonymous_lifetime_mode: AnonymousLifetimeMode, - f: F, - ) -> (hir::Generics<'hir>, T) - where - F: FnOnce(&mut Self, &mut Vec>) -> T, - { + f: impl FnOnce(&mut Self, &mut Vec>) -> T, + ) -> (hir::Generics<'hir>, T) { let (in_band_defs, (mut lowered_generics, res)) = self.with_in_scope_lifetime_defs(&generics.params, |this| { this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| { @@ -917,10 +911,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (lowered_generics, res) } - fn with_dyn_type_scope(&mut self, in_scope: bool, f: F) -> T - where - F: FnOnce(&mut Self) -> T, - { + fn with_dyn_type_scope(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T { let was_in_dyn_type = self.is_in_dyn_type; self.is_in_dyn_type = in_scope; @@ -931,10 +922,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { result } - fn with_new_scopes(&mut self, f: F) -> T - where - F: FnOnce(&mut Self) -> T, - { + fn with_new_scopes(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; From 956265d55b7c2039eaa2476cfc3b370ead322ce4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 6 Jan 2020 05:35:18 +0100 Subject: [PATCH 20/48] lowering: elide some lifetimes --- src/librustc_ast_lowering/item.rs | 4 ++-- src/librustc_ast_lowering/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 7aef4b11ae3f9..e8d6c65e8de7d 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -25,7 +25,7 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>, } -impl<'a, 'lowering, 'hir> ItemLowerer<'a, 'lowering, 'hir> { +impl ItemLowerer<'_, '_, '_> { fn with_trait_impl_ref(&mut self, impl_ref: &Option, f: impl FnOnce(&mut Self)) { let old = self.lctx.is_in_trait_impl; self.lctx.is_in_trait_impl = if let &None = impl_ref { false } else { true }; @@ -34,7 +34,7 @@ impl<'a, 'lowering, 'hir> ItemLowerer<'a, 'lowering, 'hir> { } } -impl<'a, 'lowering, 'hir> Visitor<'a> for ItemLowerer<'a, 'lowering, 'hir> { +impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { fn visit_mod(&mut self, m: &'a Mod, _s: Span, _attrs: &[Attribute], n: NodeId) { let hir_id = self.lctx.lower_node_id(n); diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 5b68018683c47..c4b992243690f 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -445,7 +445,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - impl<'tcx, 'lowering, 'hir> Visitor<'tcx> for MiscCollector<'tcx, 'lowering, 'hir> { + impl<'tcx> Visitor<'tcx> for MiscCollector<'tcx, '_, '_> { fn visit_pat(&mut self, p: &'tcx Pat) { if let PatKind::Paren(..) | PatKind::Rest = p.kind { // Doesn't generate a HIR node From f75ccdef10148637165eec034d9346cbb82e0119 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 6 Jan 2020 05:51:59 +0100 Subject: [PATCH 21/48] extract pattern lowering -> pat.rs --- src/librustc_ast_lowering/lib.rs | 249 +----------------------------- src/librustc_ast_lowering/pat.rs | 253 +++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+), 246 deletions(-) create mode 100644 src/librustc_ast_lowering/pat.rs diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index c4b992243690f..658bcb26ecfcd 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -33,6 +33,7 @@ //! in the HIR, especially for multiple identifiers. #![feature(array_value_iter)] +#![feature(crate_visibility_modifier)] use rustc::arena::Arena; use rustc::dep_graph::DepGraph; @@ -58,14 +59,13 @@ use rustc_session::config::nightly_options; use rustc_session::node_id::NodeMap; use rustc_session::Session; use rustc_span::hygiene::ExpnId; -use rustc_span::source_map::{respan, DesugaringKind, ExpnData, ExpnKind, Spanned}; +use rustc_span::source_map::{respan, DesugaringKind, ExpnData, ExpnKind}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use syntax::ast; use syntax::ast::*; use syntax::attr; use syntax::print::pprust; -use syntax::ptr::P as AstP; use syntax::sess::ParseSess; use syntax::token::{self, Nonterminal, Token}; use syntax::tokenstream::{TokenStream, TokenTree}; @@ -86,6 +86,7 @@ macro_rules! arena_vec { mod expr; mod item; +mod pat; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; @@ -2636,250 +2637,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.expr_block(block, AttrVec::new()) } - fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { - let node = match p.kind { - PatKind::Wild => hir::PatKind::Wild, - PatKind::Ident(ref binding_mode, ident, ref sub) => { - let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); - let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub); - node - } - PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)), - PatKind::TupleStruct(ref path, ref pats) => { - let qpath = self.lower_qpath( - p.id, - &None, - path, - ParamMode::Optional, - ImplTraitContext::disallowed(), - ); - let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); - hir::PatKind::TupleStruct(qpath, pats, ddpos) - } - PatKind::Or(ref pats) => { - hir::PatKind::Or(self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x)))) - } - PatKind::Path(ref qself, ref path) => { - let qpath = self.lower_qpath( - p.id, - qself, - path, - ParamMode::Optional, - ImplTraitContext::disallowed(), - ); - hir::PatKind::Path(qpath) - } - PatKind::Struct(ref path, ref fields, etc) => { - let qpath = self.lower_qpath( - p.id, - &None, - path, - ParamMode::Optional, - ImplTraitContext::disallowed(), - ); - - let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat { - hir_id: self.next_id(), - ident: f.ident, - pat: self.lower_pat(&f.pat), - is_shorthand: f.is_shorthand, - span: f.span, - })); - hir::PatKind::Struct(qpath, fs, etc) - } - PatKind::Tuple(ref pats) => { - let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple"); - hir::PatKind::Tuple(pats, ddpos) - } - PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)), - PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl), - PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => hir::PatKind::Range( - self.lower_expr(e1), - self.lower_expr(e2), - self.lower_range_end(end), - ), - PatKind::Slice(ref pats) => self.lower_pat_slice(pats), - PatKind::Rest => { - // If we reach here the `..` pattern is not semantically allowed. - self.ban_illegal_rest_pat(p.span) - } - PatKind::Paren(ref inner) => return self.lower_pat(inner), - PatKind::Mac(_) => panic!("Shouldn't exist here"), - }; - - self.pat_with_node_id_of(p, node) - } - - fn lower_pat_tuple( - &mut self, - pats: &[AstP], - ctx: &str, - ) -> (&'hir [&'hir hir::Pat<'hir>], Option) { - let mut elems = Vec::with_capacity(pats.len()); - let mut rest = None; - - let mut iter = pats.iter().enumerate(); - for (idx, pat) in iter.by_ref() { - // Interpret the first `..` pattern as a sub-tuple pattern. - // Note that unlike for slice patterns, - // where `xs @ ..` is a legal sub-slice pattern, - // it is not a legal sub-tuple pattern. - if pat.is_rest() { - rest = Some((idx, pat.span)); - break; - } - // It was not a sub-tuple pattern so lower it normally. - elems.push(self.lower_pat(pat)); - } - - for (_, pat) in iter { - // There was a previous sub-tuple pattern; make sure we don't allow more... - if pat.is_rest() { - // ...but there was one again, so error. - self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx); - } else { - elems.push(self.lower_pat(pat)); - } - } - - (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos)) - } - - /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into - /// `hir::PatKind::Slice(before, slice, after)`. - /// - /// When encountering `($binding_mode $ident @)? ..` (`slice`), - /// this is interpreted as a sub-slice pattern semantically. - /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`. - fn lower_pat_slice(&mut self, pats: &[AstP]) -> hir::PatKind<'hir> { - let mut before = Vec::new(); - let mut after = Vec::new(); - let mut slice = None; - let mut prev_rest_span = None; - - let mut iter = pats.iter(); - // Lower all the patterns until the first occurence of a sub-slice pattern. - for pat in iter.by_ref() { - match pat.kind { - // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here. - PatKind::Rest => { - prev_rest_span = Some(pat.span); - slice = Some(self.pat_wild_with_node_id_of(pat)); - break; - } - // Found a sub-slice pattern `$binding_mode $ident @ ..`. - // Record, lower it to `$binding_mode $ident @ _`, and stop here. - PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => { - prev_rest_span = Some(sub.span); - let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub)); - let node = self.lower_pat_ident(pat, bm, ident, lower_sub); - slice = Some(self.pat_with_node_id_of(pat, node)); - break; - } - // It was not a subslice pattern so lower it normally. - _ => before.push(self.lower_pat(pat)), - } - } - - // Lower all the patterns after the first sub-slice pattern. - for pat in iter { - // There was a previous subslice pattern; make sure we don't allow more. - let rest_span = match pat.kind { - PatKind::Rest => Some(pat.span), - PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => { - // The `HirValidator` is merciless; add a `_` pattern to avoid ICEs. - after.push(self.pat_wild_with_node_id_of(pat)); - Some(sub.span) - } - _ => None, - }; - if let Some(rest_span) = rest_span { - // We have e.g., `[a, .., b, ..]`. That's no good, error! - self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice"); - } else { - // Lower the pattern normally. - after.push(self.lower_pat(pat)); - } - } - - hir::PatKind::Slice( - self.arena.alloc_from_iter(before), - slice, - self.arena.alloc_from_iter(after), - ) - } - - fn lower_pat_ident( - &mut self, - p: &Pat, - binding_mode: &BindingMode, - ident: Ident, - lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>, - ) -> hir::PatKind<'hir> { - match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) { - // `None` can occur in body-less function signatures - res @ None | res @ Some(Res::Local(_)) => { - let canonical_id = match res { - Some(Res::Local(id)) => id, - _ => p.id, - }; - - hir::PatKind::Binding( - self.lower_binding_mode(binding_mode), - self.lower_node_id(canonical_id), - ident, - lower_sub(self), - ) - } - Some(res) => hir::PatKind::Path(hir::QPath::Resolved( - None, - self.arena.alloc(hir::Path { - span: ident.span, - res: self.lower_res(res), - segments: arena_vec![self; hir::PathSegment::from_ident(ident)], - }), - )), - } - } - - fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { - self.pat_with_node_id_of(p, hir::PatKind::Wild) - } - - /// Construct a `Pat` with the `HirId` of `p.id` lowered. - fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> { - self.arena.alloc(hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span }) - } - - /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. - fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) { - self.diagnostic() - .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx)) - .span_label(sp, &format!("can only be used once per {} pattern", ctx)) - .span_label(prev_sp, "previously used here") - .emit(); - } - - /// Used to ban the `..` pattern in places it shouldn't be semantically. - fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> { - self.diagnostic() - .struct_span_err(sp, "`..` patterns are not allowed here") - .note("only allowed in tuple, tuple struct, and slice patterns") - .emit(); - - // We're not in a list context so `..` can be reasonably treated - // as `_` because it should always be valid and roughly matches the - // intent of `..` (notice that the rest of a single slot is that slot). - hir::PatKind::Wild - } - - fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd { - match *e { - RangeEnd::Included(_) => hir::RangeEnd::Included, - RangeEnd::Excluded => hir::RangeEnd::Excluded, - } - } - fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst { self.with_new_scopes(|this| hir::AnonConst { hir_id: this.lower_node_id(c.id), diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs new file mode 100644 index 0000000000000..3a3ffd7560bab --- /dev/null +++ b/src/librustc_ast_lowering/pat.rs @@ -0,0 +1,253 @@ +use super::{ImplTraitContext, LoweringContext, ParamMode}; + +use rustc::hir; +use rustc::hir::def::Res; +use rustc_span::{source_map::Spanned, Span}; +use syntax::ast::*; +use syntax::ptr::P; + +impl<'a, 'hir> LoweringContext<'a, 'hir> { + crate fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { + let node = match p.kind { + PatKind::Wild => hir::PatKind::Wild, + PatKind::Ident(ref binding_mode, ident, ref sub) => { + let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); + let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub); + node + } + PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)), + PatKind::TupleStruct(ref path, ref pats) => { + let qpath = self.lower_qpath( + p.id, + &None, + path, + ParamMode::Optional, + ImplTraitContext::disallowed(), + ); + let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); + hir::PatKind::TupleStruct(qpath, pats, ddpos) + } + PatKind::Or(ref pats) => { + hir::PatKind::Or(self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x)))) + } + PatKind::Path(ref qself, ref path) => { + let qpath = self.lower_qpath( + p.id, + qself, + path, + ParamMode::Optional, + ImplTraitContext::disallowed(), + ); + hir::PatKind::Path(qpath) + } + PatKind::Struct(ref path, ref fields, etc) => { + let qpath = self.lower_qpath( + p.id, + &None, + path, + ParamMode::Optional, + ImplTraitContext::disallowed(), + ); + + let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat { + hir_id: self.next_id(), + ident: f.ident, + pat: self.lower_pat(&f.pat), + is_shorthand: f.is_shorthand, + span: f.span, + })); + hir::PatKind::Struct(qpath, fs, etc) + } + PatKind::Tuple(ref pats) => { + let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple"); + hir::PatKind::Tuple(pats, ddpos) + } + PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)), + PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl), + PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => hir::PatKind::Range( + self.lower_expr(e1), + self.lower_expr(e2), + self.lower_range_end(end), + ), + PatKind::Slice(ref pats) => self.lower_pat_slice(pats), + PatKind::Rest => { + // If we reach here the `..` pattern is not semantically allowed. + self.ban_illegal_rest_pat(p.span) + } + PatKind::Paren(ref inner) => return self.lower_pat(inner), + PatKind::Mac(_) => panic!("Shouldn't exist here"), + }; + + self.pat_with_node_id_of(p, node) + } + + fn lower_pat_tuple( + &mut self, + pats: &[P], + ctx: &str, + ) -> (&'hir [&'hir hir::Pat<'hir>], Option) { + let mut elems = Vec::with_capacity(pats.len()); + let mut rest = None; + + let mut iter = pats.iter().enumerate(); + for (idx, pat) in iter.by_ref() { + // Interpret the first `..` pattern as a sub-tuple pattern. + // Note that unlike for slice patterns, + // where `xs @ ..` is a legal sub-slice pattern, + // it is not a legal sub-tuple pattern. + if pat.is_rest() { + rest = Some((idx, pat.span)); + break; + } + // It was not a sub-tuple pattern so lower it normally. + elems.push(self.lower_pat(pat)); + } + + for (_, pat) in iter { + // There was a previous sub-tuple pattern; make sure we don't allow more... + if pat.is_rest() { + // ...but there was one again, so error. + self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx); + } else { + elems.push(self.lower_pat(pat)); + } + } + + (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos)) + } + + /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into + /// `hir::PatKind::Slice(before, slice, after)`. + /// + /// When encountering `($binding_mode $ident @)? ..` (`slice`), + /// this is interpreted as a sub-slice pattern semantically. + /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`. + fn lower_pat_slice(&mut self, pats: &[P]) -> hir::PatKind<'hir> { + let mut before = Vec::new(); + let mut after = Vec::new(); + let mut slice = None; + let mut prev_rest_span = None; + + let mut iter = pats.iter(); + // Lower all the patterns until the first occurence of a sub-slice pattern. + for pat in iter.by_ref() { + match pat.kind { + // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here. + PatKind::Rest => { + prev_rest_span = Some(pat.span); + slice = Some(self.pat_wild_with_node_id_of(pat)); + break; + } + // Found a sub-slice pattern `$binding_mode $ident @ ..`. + // Record, lower it to `$binding_mode $ident @ _`, and stop here. + PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => { + prev_rest_span = Some(sub.span); + let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub)); + let node = self.lower_pat_ident(pat, bm, ident, lower_sub); + slice = Some(self.pat_with_node_id_of(pat, node)); + break; + } + // It was not a subslice pattern so lower it normally. + _ => before.push(self.lower_pat(pat)), + } + } + + // Lower all the patterns after the first sub-slice pattern. + for pat in iter { + // There was a previous subslice pattern; make sure we don't allow more. + let rest_span = match pat.kind { + PatKind::Rest => Some(pat.span), + PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => { + // The `HirValidator` is merciless; add a `_` pattern to avoid ICEs. + after.push(self.pat_wild_with_node_id_of(pat)); + Some(sub.span) + } + _ => None, + }; + if let Some(rest_span) = rest_span { + // We have e.g., `[a, .., b, ..]`. That's no good, error! + self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice"); + } else { + // Lower the pattern normally. + after.push(self.lower_pat(pat)); + } + } + + hir::PatKind::Slice( + self.arena.alloc_from_iter(before), + slice, + self.arena.alloc_from_iter(after), + ) + } + + fn lower_pat_ident( + &mut self, + p: &Pat, + binding_mode: &BindingMode, + ident: Ident, + lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>, + ) -> hir::PatKind<'hir> { + match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) { + // `None` can occur in body-less function signatures + res @ None | res @ Some(Res::Local(_)) => { + let canonical_id = match res { + Some(Res::Local(id)) => id, + _ => p.id, + }; + + hir::PatKind::Binding( + self.lower_binding_mode(binding_mode), + self.lower_node_id(canonical_id), + ident, + lower_sub(self), + ) + } + Some(res) => hir::PatKind::Path(hir::QPath::Resolved( + None, + self.arena.alloc(hir::Path { + span: ident.span, + res: self.lower_res(res), + segments: arena_vec![self; hir::PathSegment::from_ident(ident)], + }), + )), + } + } + + fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { + self.pat_with_node_id_of(p, hir::PatKind::Wild) + } + + /// Construct a `Pat` with the `HirId` of `p.id` lowered. + fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> { + self.arena.alloc(hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span }) + } + + /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. + fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) { + self.diagnostic() + .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx)) + .span_label(sp, &format!("can only be used once per {} pattern", ctx)) + .span_label(prev_sp, "previously used here") + .emit(); + } + + /// Used to ban the `..` pattern in places it shouldn't be semantically. + fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> { + self.diagnostic() + .struct_span_err(sp, "`..` patterns are not allowed here") + .note("only allowed in tuple, tuple struct, and slice patterns") + .emit(); + + // We're not in a list context so `..` can be reasonably treated + // as `_` because it should always be valid and roughly matches the + // intent of `..` (notice that the rest of a single slot is that slot). + hir::PatKind::Wild + } + + fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd { + match *e { + RangeEnd::Included(_) => hir::RangeEnd::Included, + RangeEnd::Excluded => hir::RangeEnd::Excluded, + } + } +} From ae6e31b1a339903a92bb03ee085924e3da425356 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 6 Jan 2020 06:54:48 +0100 Subject: [PATCH 22/48] move lower_binding_mode -> pat.rs --- src/librustc_ast_lowering/lib.rs | 9 --------- src/librustc_ast_lowering/pat.rs | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 658bcb26ecfcd..3431cf08b6d1e 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -2696,15 +2696,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation { - match *b { - BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated, - BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref, - BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable, - BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut, - } - } - fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource { match u { CompilerGenerated => hir::UnsafeSource::CompilerGenerated, diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs index 3a3ffd7560bab..4d7d21abc8c94 100644 --- a/src/librustc_ast_lowering/pat.rs +++ b/src/librustc_ast_lowering/pat.rs @@ -213,6 +213,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation { + match *b { + BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated, + BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref, + BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable, + BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut, + } + } + fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { self.pat_with_node_id_of(p, hir::PatKind::Wild) } From 4e6329ec3a7d971972e0a876ae3e6b86ad506d82 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 6 Jan 2020 06:28:43 +0100 Subject: [PATCH 23/48] extract path lowering -> path.rs --- src/librustc_ast_lowering/lib.rs | 404 +--------------------------- src/librustc_ast_lowering/pat.rs | 4 +- src/librustc_ast_lowering/path.rs | 421 ++++++++++++++++++++++++++++++ 3 files changed, 426 insertions(+), 403 deletions(-) create mode 100644 src/librustc_ast_lowering/path.rs diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 3431cf08b6d1e..3211c57f6bbb0 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! Lowers the AST to the HIR. //! //! Since the AST and HIR are fairly similar, this is mostly a simple procedure, @@ -40,7 +38,7 @@ use rustc::dep_graph::DepGraph; use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions}; use rustc::hir::map::Map; use rustc::lint; -use rustc::lint::builtin::{self, ELIDED_LIFETIMES_IN_PATHS}; +use rustc::lint::builtin; use rustc::middle::cstore::CrateStore; use rustc::util::captures::Captures; use rustc::util::common::FN_OUTPUT_NAME; @@ -48,7 +46,7 @@ use rustc::{bug, span_bug}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_error_codes::*; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIndex, CRATE_DEF_INDEX}; @@ -87,6 +85,7 @@ macro_rules! arena_vec { mod expr; mod item; mod pat; +mod path; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; @@ -1624,403 +1623,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } - fn lower_qpath( - &mut self, - id: NodeId, - qself: &Option, - p: &Path, - param_mode: ParamMode, - mut itctx: ImplTraitContext<'_, 'hir>, - ) -> hir::QPath<'hir> { - let qself_position = qself.as_ref().map(|q| q.position); - let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow())); - - let partial_res = - self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); - - let proj_start = p.segments.len() - partial_res.unresolved_segments(); - let path = self.arena.alloc(hir::Path { - res: self.lower_res(partial_res.base_res()), - segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map( - |(i, segment)| { - let param_mode = match (qself_position, param_mode) { - (Some(j), ParamMode::Optional) if i < j => { - // This segment is part of the trait path in a - // qualified path - one of `a`, `b` or `Trait` - // in `::T::U::method`. - ParamMode::Explicit - } - _ => param_mode, - }; - - // Figure out if this is a type/trait segment, - // which may need lifetime elision performed. - let parent_def_id = |this: &mut Self, def_id: DefId| DefId { - krate: def_id.krate, - index: this.def_key(def_id).parent.expect("missing parent"), - }; - let type_def_id = match partial_res.base_res() { - Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => { - Some(parent_def_id(self, def_id)) - } - Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => { - Some(parent_def_id(self, def_id)) - } - Res::Def(DefKind::Struct, def_id) - | Res::Def(DefKind::Union, def_id) - | Res::Def(DefKind::Enum, def_id) - | Res::Def(DefKind::TyAlias, def_id) - | Res::Def(DefKind::Trait, def_id) - if i + 1 == proj_start => - { - Some(def_id) - } - _ => None, - }; - let parenthesized_generic_args = match partial_res.base_res() { - // `a::b::Trait(Args)` - Res::Def(DefKind::Trait, _) if i + 1 == proj_start => { - ParenthesizedGenericArgs::Ok - } - // `a::b::Trait(Args)::TraitItem` - Res::Def(DefKind::Method, _) - | Res::Def(DefKind::AssocConst, _) - | Res::Def(DefKind::AssocTy, _) - if i + 2 == proj_start => - { - ParenthesizedGenericArgs::Ok - } - // Avoid duplicated errors. - Res::Err => ParenthesizedGenericArgs::Ok, - // An error - _ => ParenthesizedGenericArgs::Err, - }; - - let num_lifetimes = type_def_id.map_or(0, |def_id| { - if let Some(&n) = self.type_def_lifetime_params.get(&def_id) { - return n; - } - assert!(!def_id.is_local()); - let item_generics = self - .resolver - .cstore() - .item_generics_cloned_untracked(def_id, self.sess); - let n = item_generics.own_counts().lifetimes; - self.type_def_lifetime_params.insert(def_id, n); - n - }); - self.lower_path_segment( - p.span, - segment, - param_mode, - num_lifetimes, - parenthesized_generic_args, - itctx.reborrow(), - None, - ) - }, - )), - span: p.span, - }); - - // Simple case, either no projections, or only fully-qualified. - // E.g., `std::mem::size_of` or `::Item`. - if partial_res.unresolved_segments() == 0 { - return hir::QPath::Resolved(qself, path); - } - - // Create the innermost type that we're projecting from. - let mut ty = if path.segments.is_empty() { - // If the base path is empty that means there exists a - // syntactical `Self`, e.g., `&i32` in `<&i32>::clone`. - qself.expect("missing QSelf for ::...") - } else { - // Otherwise, the base path is an implicit `Self` type path, - // e.g., `Vec` in `Vec::new` or `::Item` in - // `::Item::default`. - let new_id = self.next_id(); - self.arena.alloc(self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path))) - }; - - // Anything after the base path are associated "extensions", - // out of which all but the last one are associated types, - // e.g., for `std::vec::Vec::::IntoIter::Item::clone`: - // * base path is `std::vec::Vec` - // * "extensions" are `IntoIter`, `Item` and `clone` - // * type nodes are: - // 1. `std::vec::Vec` (created above) - // 2. `>::IntoIter` - // 3. `<>::IntoIter>::Item` - // * final path is `<<>::IntoIter>::Item>::clone` - for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { - let segment = self.arena.alloc(self.lower_path_segment( - p.span, - segment, - param_mode, - 0, - ParenthesizedGenericArgs::Err, - itctx.reborrow(), - None, - )); - let qpath = hir::QPath::TypeRelative(ty, segment); - - // It's finished, return the extension of the right node type. - if i == p.segments.len() - 1 { - return qpath; - } - - // Wrap the associated extension in another type node. - let new_id = self.next_id(); - ty = self.arena.alloc(self.ty_path(new_id, p.span, qpath)); - } - - // We should've returned in the for loop above. - span_bug!( - p.span, - "lower_qpath: no final extension segment in {}..{}", - proj_start, - p.segments.len() - ) - } - - fn lower_path_extra( - &mut self, - res: Res, - p: &Path, - param_mode: ParamMode, - explicit_owner: Option, - ) -> &'hir hir::Path<'hir> { - self.arena.alloc(hir::Path { - res, - segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| { - self.lower_path_segment( - p.span, - segment, - param_mode, - 0, - ParenthesizedGenericArgs::Err, - ImplTraitContext::disallowed(), - explicit_owner, - ) - })), - span: p.span, - }) - } - - fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> &'hir hir::Path<'hir> { - let res = self.expect_full_res(id); - let res = self.lower_res(res); - self.lower_path_extra(res, p, param_mode, None) - } - - fn lower_path_segment( - &mut self, - path_span: Span, - segment: &PathSegment, - param_mode: ParamMode, - expected_lifetimes: usize, - parenthesized_generic_args: ParenthesizedGenericArgs, - itctx: ImplTraitContext<'_, 'hir>, - explicit_owner: Option, - ) -> hir::PathSegment<'hir> { - let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args { - let msg = "parenthesized type parameters may only be used with a `Fn` trait"; - match **generic_args { - GenericArgs::AngleBracketed(ref data) => { - self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) - } - GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { - ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), - ParenthesizedGenericArgs::Err => { - let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg); - err.span_label(data.span, "only `Fn` traits may use parentheses"); - if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) { - // Do not suggest going from `Trait()` to `Trait<>` - if data.inputs.len() > 0 { - if let Some(split) = snippet.find('(') { - let trait_name = &snippet[0..split]; - let args = &snippet[split + 1..snippet.len() - 1]; - err.span_suggestion( - data.span, - "use angle brackets instead", - format!("{}<{}>", trait_name, args), - Applicability::MaybeIncorrect, - ); - } - } - }; - err.emit(); - ( - self.lower_angle_bracketed_parameter_data( - &data.as_angle_bracketed_args(), - param_mode, - itctx, - ) - .0, - false, - ) - } - }, - } - } else { - self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx) - }; - - let has_lifetimes = generic_args.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }); - let first_generic_span = generic_args - .args - .iter() - .map(|a| a.span()) - .chain(generic_args.bindings.iter().map(|b| b.span)) - .next(); - if !generic_args.parenthesized && !has_lifetimes { - generic_args.args = self - .elided_path_lifetimes(path_span, expected_lifetimes) - .map(|lt| GenericArg::Lifetime(lt)) - .chain(generic_args.args.into_iter()) - .collect(); - if expected_lifetimes > 0 && param_mode == ParamMode::Explicit { - let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", "); - let no_non_lt_args = generic_args.args.len() == expected_lifetimes; - let no_bindings = generic_args.bindings.is_empty(); - let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings { - // If there are no (non-implicit) generic args or associated type - // bindings, our suggestion includes the angle brackets. - (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion)) - } else { - // Otherwise (sorry, this is kind of gross) we need to infer the - // place to splice in the `'_, ` from the generics that do exist. - let first_generic_span = first_generic_span - .expect("already checked that non-lifetime args or bindings exist"); - (false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion)) - }; - match self.anonymous_lifetime_mode { - // In create-parameter mode we error here because we don't want to support - // deprecated impl elision in new features like impl elision and `async fn`, - // both of which work using the `CreateParameter` mode: - // - // impl Foo for std::cell::Ref // note lack of '_ - // async fn foo(_: std::cell::Ref) { ... } - AnonymousLifetimeMode::CreateParameter => { - let mut err = struct_span_err!( - self.sess, - path_span, - E0726, - "implicit elided lifetime not allowed here" - ); - crate::lint::builtin::add_elided_lifetime_in_path_suggestion( - &self.sess, - &mut err, - expected_lifetimes, - path_span, - incl_angl_brckt, - insertion_sp, - suggestion, - ); - err.emit(); - } - AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => { - self.resolver.lint_buffer().buffer_lint_with_diagnostic( - ELIDED_LIFETIMES_IN_PATHS, - CRATE_NODE_ID, - path_span, - "hidden lifetime parameters in types are deprecated", - builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths( - expected_lifetimes, - path_span, - incl_angl_brckt, - insertion_sp, - suggestion, - ), - ); - } - } - } - } - - let res = self.expect_full_res(segment.id); - let id = if let Some(owner) = explicit_owner { - self.lower_node_id_with_owner(segment.id, owner) - } else { - self.lower_node_id(segment.id) - }; - debug!( - "lower_path_segment: ident={:?} original-id={:?} new-id={:?}", - segment.ident, segment.id, id, - ); - - hir::PathSegment { - ident: segment.ident, - hir_id: Some(id), - res: Some(self.lower_res(res)), - infer_args, - args: if generic_args.is_empty() { - None - } else { - Some(self.arena.alloc(generic_args.into_generic_args(self.arena))) - }, - } - } - - fn lower_angle_bracketed_parameter_data( - &mut self, - data: &AngleBracketedArgs, - param_mode: ParamMode, - mut itctx: ImplTraitContext<'_, 'hir>, - ) -> (GenericArgsCtor<'hir>, bool) { - let &AngleBracketedArgs { ref args, ref constraints, .. } = data; - let has_non_lt_args = args.iter().any(|arg| match arg { - ast::GenericArg::Lifetime(_) => false, - ast::GenericArg::Type(_) => true, - ast::GenericArg::Const(_) => true, - }); - ( - GenericArgsCtor { - args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(), - bindings: self.arena.alloc_from_iter( - constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())), - ), - parenthesized: false, - }, - !has_non_lt_args && param_mode == ParamMode::Optional, - ) - } - - fn lower_parenthesized_parameter_data( - &mut self, - data: &ParenthesizedArgs, - ) -> (GenericArgsCtor<'hir>, bool) { - // Switch to `PassThrough` mode for anonymous lifetimes; this - // means that we permit things like `&Ref`, where `Ref` has - // a hidden lifetime parameter. This is needed for backwards - // compatibility, even in contexts like an impl header where - // we generally don't permit such things (see #51008). - self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| { - let &ParenthesizedArgs { ref inputs, ref output, span } = data; - let inputs = this.arena.alloc_from_iter( - inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())), - ); - let output_ty = match output { - FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()), - FunctionRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])), - }; - let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))]; - let binding = hir::TypeBinding { - hir_id: this.next_id(), - ident: Ident::with_dummy_span(FN_OUTPUT_NAME), - span: output_ty.span, - kind: hir::TypeBindingKind::Equality { ty: output_ty }, - }; - ( - GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true }, - false, - ) - }) - } - fn lower_local(&mut self, l: &Local) -> (hir::Local<'hir>, SmallVec<[NodeId; 1]>) { let mut ids = SmallVec::<[NodeId; 1]>::new(); if self.sess.features_untracked().impl_trait_in_bindings { diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs index 4d7d21abc8c94..cd69646d0c53a 100644 --- a/src/librustc_ast_lowering/pat.rs +++ b/src/librustc_ast_lowering/pat.rs @@ -1,7 +1,7 @@ use super::{ImplTraitContext, LoweringContext, ParamMode}; -use rustc::hir; -use rustc::hir::def::Res; +use rustc_hir as hir; +use rustc_hir::def::Res; use rustc_span::{source_map::Spanned, Span}; use syntax::ast::*; use syntax::ptr::P; diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs new file mode 100644 index 0000000000000..7209dbfdcc78f --- /dev/null +++ b/src/librustc_ast_lowering/path.rs @@ -0,0 +1,421 @@ +use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode}; +use super::{GenericArgsCtor, ParenthesizedGenericArgs}; + +use rustc::lint::builtin::{self, ELIDED_LIFETIMES_IN_PATHS}; +use rustc::span_bug; +use rustc::util::common::FN_OUTPUT_NAME; +use rustc_error_codes::*; +use rustc_errors::{struct_span_err, Applicability}; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, PartialRes, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::GenericArg; +use rustc_span::Span; +use syntax::ast::{self, *}; + +use log::debug; +use smallvec::smallvec; + +impl<'a, 'hir> LoweringContext<'a, 'hir> { + crate fn lower_qpath( + &mut self, + id: NodeId, + qself: &Option, + p: &Path, + param_mode: ParamMode, + mut itctx: ImplTraitContext<'_, 'hir>, + ) -> hir::QPath<'hir> { + let qself_position = qself.as_ref().map(|q| q.position); + let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow())); + + let partial_res = + self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); + + let proj_start = p.segments.len() - partial_res.unresolved_segments(); + let path = self.arena.alloc(hir::Path { + res: self.lower_res(partial_res.base_res()), + segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map( + |(i, segment)| { + let param_mode = match (qself_position, param_mode) { + (Some(j), ParamMode::Optional) if i < j => { + // This segment is part of the trait path in a + // qualified path - one of `a`, `b` or `Trait` + // in `::T::U::method`. + ParamMode::Explicit + } + _ => param_mode, + }; + + // Figure out if this is a type/trait segment, + // which may need lifetime elision performed. + let parent_def_id = |this: &mut Self, def_id: DefId| DefId { + krate: def_id.krate, + index: this.def_key(def_id).parent.expect("missing parent"), + }; + let type_def_id = match partial_res.base_res() { + Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => { + Some(parent_def_id(self, def_id)) + } + Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => { + Some(parent_def_id(self, def_id)) + } + Res::Def(DefKind::Struct, def_id) + | Res::Def(DefKind::Union, def_id) + | Res::Def(DefKind::Enum, def_id) + | Res::Def(DefKind::TyAlias, def_id) + | Res::Def(DefKind::Trait, def_id) + if i + 1 == proj_start => + { + Some(def_id) + } + _ => None, + }; + let parenthesized_generic_args = match partial_res.base_res() { + // `a::b::Trait(Args)` + Res::Def(DefKind::Trait, _) if i + 1 == proj_start => { + ParenthesizedGenericArgs::Ok + } + // `a::b::Trait(Args)::TraitItem` + Res::Def(DefKind::Method, _) + | Res::Def(DefKind::AssocConst, _) + | Res::Def(DefKind::AssocTy, _) + if i + 2 == proj_start => + { + ParenthesizedGenericArgs::Ok + } + // Avoid duplicated errors. + Res::Err => ParenthesizedGenericArgs::Ok, + // An error + _ => ParenthesizedGenericArgs::Err, + }; + + let num_lifetimes = type_def_id.map_or(0, |def_id| { + if let Some(&n) = self.type_def_lifetime_params.get(&def_id) { + return n; + } + assert!(!def_id.is_local()); + let item_generics = self + .resolver + .cstore() + .item_generics_cloned_untracked(def_id, self.sess); + let n = item_generics.own_counts().lifetimes; + self.type_def_lifetime_params.insert(def_id, n); + n + }); + self.lower_path_segment( + p.span, + segment, + param_mode, + num_lifetimes, + parenthesized_generic_args, + itctx.reborrow(), + None, + ) + }, + )), + span: p.span, + }); + + // Simple case, either no projections, or only fully-qualified. + // E.g., `std::mem::size_of` or `::Item`. + if partial_res.unresolved_segments() == 0 { + return hir::QPath::Resolved(qself, path); + } + + // Create the innermost type that we're projecting from. + let mut ty = if path.segments.is_empty() { + // If the base path is empty that means there exists a + // syntactical `Self`, e.g., `&i32` in `<&i32>::clone`. + qself.expect("missing QSelf for ::...") + } else { + // Otherwise, the base path is an implicit `Self` type path, + // e.g., `Vec` in `Vec::new` or `::Item` in + // `::Item::default`. + let new_id = self.next_id(); + self.arena.alloc(self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path))) + }; + + // Anything after the base path are associated "extensions", + // out of which all but the last one are associated types, + // e.g., for `std::vec::Vec::::IntoIter::Item::clone`: + // * base path is `std::vec::Vec` + // * "extensions" are `IntoIter`, `Item` and `clone` + // * type nodes are: + // 1. `std::vec::Vec` (created above) + // 2. `>::IntoIter` + // 3. `<>::IntoIter>::Item` + // * final path is `<<>::IntoIter>::Item>::clone` + for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { + let segment = self.arena.alloc(self.lower_path_segment( + p.span, + segment, + param_mode, + 0, + ParenthesizedGenericArgs::Err, + itctx.reborrow(), + None, + )); + let qpath = hir::QPath::TypeRelative(ty, segment); + + // It's finished, return the extension of the right node type. + if i == p.segments.len() - 1 { + return qpath; + } + + // Wrap the associated extension in another type node. + let new_id = self.next_id(); + ty = self.arena.alloc(self.ty_path(new_id, p.span, qpath)); + } + + // We should've returned in the for loop above. + span_bug!( + p.span, + "lower_qpath: no final extension segment in {}..{}", + proj_start, + p.segments.len() + ) + } + + crate fn lower_path_extra( + &mut self, + res: Res, + p: &Path, + param_mode: ParamMode, + explicit_owner: Option, + ) -> &'hir hir::Path<'hir> { + self.arena.alloc(hir::Path { + res, + segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| { + self.lower_path_segment( + p.span, + segment, + param_mode, + 0, + ParenthesizedGenericArgs::Err, + ImplTraitContext::disallowed(), + explicit_owner, + ) + })), + span: p.span, + }) + } + + crate fn lower_path( + &mut self, + id: NodeId, + p: &Path, + param_mode: ParamMode, + ) -> &'hir hir::Path<'hir> { + let res = self.expect_full_res(id); + let res = self.lower_res(res); + self.lower_path_extra(res, p, param_mode, None) + } + + crate fn lower_path_segment( + &mut self, + path_span: Span, + segment: &PathSegment, + param_mode: ParamMode, + expected_lifetimes: usize, + parenthesized_generic_args: ParenthesizedGenericArgs, + itctx: ImplTraitContext<'_, 'hir>, + explicit_owner: Option, + ) -> hir::PathSegment<'hir> { + let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args { + let msg = "parenthesized type parameters may only be used with a `Fn` trait"; + match **generic_args { + GenericArgs::AngleBracketed(ref data) => { + self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) + } + GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { + ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), + ParenthesizedGenericArgs::Err => { + let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg); + err.span_label(data.span, "only `Fn` traits may use parentheses"); + if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) { + // Do not suggest going from `Trait()` to `Trait<>` + if data.inputs.len() > 0 { + if let Some(split) = snippet.find('(') { + let trait_name = &snippet[0..split]; + let args = &snippet[split + 1..snippet.len() - 1]; + err.span_suggestion( + data.span, + "use angle brackets instead", + format!("{}<{}>", trait_name, args), + Applicability::MaybeIncorrect, + ); + } + } + }; + err.emit(); + ( + self.lower_angle_bracketed_parameter_data( + &data.as_angle_bracketed_args(), + param_mode, + itctx, + ) + .0, + false, + ) + } + }, + } + } else { + self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx) + }; + + let has_lifetimes = generic_args.args.iter().any(|arg| match arg { + GenericArg::Lifetime(_) => true, + _ => false, + }); + let first_generic_span = generic_args + .args + .iter() + .map(|a| a.span()) + .chain(generic_args.bindings.iter().map(|b| b.span)) + .next(); + if !generic_args.parenthesized && !has_lifetimes { + generic_args.args = self + .elided_path_lifetimes(path_span, expected_lifetimes) + .map(|lt| GenericArg::Lifetime(lt)) + .chain(generic_args.args.into_iter()) + .collect(); + if expected_lifetimes > 0 && param_mode == ParamMode::Explicit { + let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", "); + let no_non_lt_args = generic_args.args.len() == expected_lifetimes; + let no_bindings = generic_args.bindings.is_empty(); + let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings { + // If there are no (non-implicit) generic args or associated type + // bindings, our suggestion includes the angle brackets. + (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion)) + } else { + // Otherwise (sorry, this is kind of gross) we need to infer the + // place to splice in the `'_, ` from the generics that do exist. + let first_generic_span = first_generic_span + .expect("already checked that non-lifetime args or bindings exist"); + (false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion)) + }; + match self.anonymous_lifetime_mode { + // In create-parameter mode we error here because we don't want to support + // deprecated impl elision in new features like impl elision and `async fn`, + // both of which work using the `CreateParameter` mode: + // + // impl Foo for std::cell::Ref // note lack of '_ + // async fn foo(_: std::cell::Ref) { ... } + AnonymousLifetimeMode::CreateParameter => { + let mut err = struct_span_err!( + self.sess, + path_span, + E0726, + "implicit elided lifetime not allowed here" + ); + crate::lint::builtin::add_elided_lifetime_in_path_suggestion( + &self.sess, + &mut err, + expected_lifetimes, + path_span, + incl_angl_brckt, + insertion_sp, + suggestion, + ); + err.emit(); + } + AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => { + self.resolver.lint_buffer().buffer_lint_with_diagnostic( + ELIDED_LIFETIMES_IN_PATHS, + CRATE_NODE_ID, + path_span, + "hidden lifetime parameters in types are deprecated", + builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths( + expected_lifetimes, + path_span, + incl_angl_brckt, + insertion_sp, + suggestion, + ), + ); + } + } + } + } + + let res = self.expect_full_res(segment.id); + let id = if let Some(owner) = explicit_owner { + self.lower_node_id_with_owner(segment.id, owner) + } else { + self.lower_node_id(segment.id) + }; + debug!( + "lower_path_segment: ident={:?} original-id={:?} new-id={:?}", + segment.ident, segment.id, id, + ); + + hir::PathSegment { + ident: segment.ident, + hir_id: Some(id), + res: Some(self.lower_res(res)), + infer_args, + args: if generic_args.is_empty() { + None + } else { + Some(self.arena.alloc(generic_args.into_generic_args(self.arena))) + }, + } + } + + fn lower_angle_bracketed_parameter_data( + &mut self, + data: &AngleBracketedArgs, + param_mode: ParamMode, + mut itctx: ImplTraitContext<'_, 'hir>, + ) -> (GenericArgsCtor<'hir>, bool) { + let &AngleBracketedArgs { ref args, ref constraints, .. } = data; + let has_non_lt_args = args.iter().any(|arg| match arg { + ast::GenericArg::Lifetime(_) => false, + ast::GenericArg::Type(_) => true, + ast::GenericArg::Const(_) => true, + }); + ( + GenericArgsCtor { + args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(), + bindings: self.arena.alloc_from_iter( + constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())), + ), + parenthesized: false, + }, + !has_non_lt_args && param_mode == ParamMode::Optional, + ) + } + + fn lower_parenthesized_parameter_data( + &mut self, + data: &ParenthesizedArgs, + ) -> (GenericArgsCtor<'hir>, bool) { + // Switch to `PassThrough` mode for anonymous lifetimes; this + // means that we permit things like `&Ref`, where `Ref` has + // a hidden lifetime parameter. This is needed for backwards + // compatibility, even in contexts like an impl header where + // we generally don't permit such things (see #51008). + self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| { + let &ParenthesizedArgs { ref inputs, ref output, span } = data; + let inputs = this.arena.alloc_from_iter( + inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())), + ); + let output_ty = match output { + FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()), + FunctionRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])), + }; + let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))]; + let binding = hir::TypeBinding { + hir_id: this.next_id(), + ident: Ident::with_dummy_span(FN_OUTPUT_NAME), + span: output_ty.span, + kind: hir::TypeBindingKind::Equality { ty: output_ty }, + }; + ( + GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true }, + false, + ) + }) + } +} From 2db97ede2702b64426d3209ce8ec787a16cbf4e7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 6 Jan 2020 06:48:51 +0100 Subject: [PATCH 24/48] refactor 'Output = $ty' & reduce rustc dep --- src/librustc/traits/project.rs | 3 +-- src/librustc/util/common.rs | 5 ----- src/librustc_ast_lowering/lib.rs | 8 +------- src/librustc_ast_lowering/path.rs | 19 ++++++++++++------- src/librustc_hir/hir.rs | 3 +++ 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 79e1b6444a9b7..738bbd936fea4 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -17,7 +17,6 @@ use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::subst::{InternalSubsts, Subst}; use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; -use crate::util::common::FN_OUTPUT_NAME; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; @@ -1364,7 +1363,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( projection_ty: ty::ProjectionTy::from_ref_and_name( tcx, trait_ref, - Ident::with_dummy_span(FN_OUTPUT_NAME), + Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME), ), ty: ret_type, }); diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 9574685215741..9324b26a09b6f 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -5,14 +5,9 @@ use rustc_data_structures::sync::Lock; use std::fmt::Debug; use std::time::{Duration, Instant}; -use rustc_span::symbol::{sym, Symbol}; - #[cfg(test)] mod tests; -// The name of the associated type for `Fn` return types. -pub const FN_OUTPUT_NAME: Symbol = sym::Output; - pub use errors::ErrorReported; pub fn to_readable_str(mut val: usize) -> String { diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 3211c57f6bbb0..062b093b8e68d 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -41,7 +41,6 @@ use rustc::lint; use rustc::lint::builtin; use rustc::middle::cstore::CrateStore; use rustc::util::captures::Captures; -use rustc::util::common::FN_OUTPUT_NAME; use rustc::{bug, span_bug}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; @@ -1978,12 +1977,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // "" let future_params = self.arena.alloc(hir::GenericArgs { args: &[], - bindings: arena_vec![self; hir::TypeBinding { - ident: Ident::with_dummy_span(FN_OUTPUT_NAME), - kind: hir::TypeBindingKind::Equality { ty: output_ty }, - hir_id: self.next_id(), - span, - }], + bindings: arena_vec![self; self.output_ty_binding(span, output_ty)], parenthesized: false, }); diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs index 7209dbfdcc78f..4f71910b0bfe2 100644 --- a/src/librustc_ast_lowering/path.rs +++ b/src/librustc_ast_lowering/path.rs @@ -3,7 +3,6 @@ use super::{GenericArgsCtor, ParenthesizedGenericArgs}; use rustc::lint::builtin::{self, ELIDED_LIFETIMES_IN_PATHS}; use rustc::span_bug; -use rustc::util::common::FN_OUTPUT_NAME; use rustc_error_codes::*; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; @@ -406,16 +405,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { FunctionRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])), }; let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))]; - let binding = hir::TypeBinding { - hir_id: this.next_id(), - ident: Ident::with_dummy_span(FN_OUTPUT_NAME), - span: output_ty.span, - kind: hir::TypeBindingKind::Equality { ty: output_ty }, - }; + let binding = this.output_ty_binding(output_ty.span, output_ty); ( GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true }, false, ) }) } + + /// An associated type binding `Output = $ty`. + crate fn output_ty_binding( + &mut self, + span: Span, + ty: &'hir hir::Ty<'hir>, + ) -> hir::TypeBinding<'hir> { + let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME); + let kind = hir::TypeBindingKind::Equality { ty }; + hir::TypeBinding { hir_id: self.next_id(), span, ident, kind } + } } diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 2303a85df4acf..603c21188e3ac 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -1875,6 +1875,9 @@ pub enum ImplItemKind<'hir> { OpaqueTy(GenericBounds<'hir>), } +// The name of the associated type for `Fn` return types. +pub const FN_OUTPUT_NAME: Symbol = sym::Output; + /// Bind a type to an associated type (i.e., `A = Foo`). /// /// Bindings like `A: Debug` are represented as a special type `A = From 69b1e5cc3d3aea6cccd8567d89cc75288f596c2e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 6 Jan 2020 07:03:46 +0100 Subject: [PATCH 25/48] {rustc::util -> rustc_data_structures}::captures --- src/librustc/infer/canonical/query_response.rs | 2 +- src/librustc/infer/outlives/verify.rs | 2 +- src/librustc/lib.rs | 1 - src/librustc/ty/mod.rs | 2 +- src/librustc/ty/sty.rs | 5 ++--- src/librustc_ast_lowering/lib.rs | 4 +++- src/{librustc/util => librustc_data_structures}/captures.rs | 0 src/librustc_data_structures/lib.rs | 1 + src/librustc_metadata/rmeta/decoder.rs | 2 +- src/librustc_mir/hair/pattern/_match.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- 12 files changed, 13 insertions(+), 12 deletions(-) rename src/{librustc/util => librustc_data_structures}/captures.rs (100%) diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 5e402dc79a1ad..012900f8af51b 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -22,7 +22,7 @@ use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use crate::ty::fold::TypeFoldable; use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::{self, BoundVar, Ty, TyCtxt}; -use crate::util::captures::Captures; +use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; use rustc_span::DUMMY_SP; diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs index 0380d0e35e78d..8ee8482e79dbc 100644 --- a/src/librustc/infer/outlives/verify.rs +++ b/src/librustc/infer/outlives/verify.rs @@ -3,7 +3,7 @@ use crate::infer::{GenericKind, VerifyBound}; use crate::traits; use crate::ty::subst::{InternalSubsts, Subst}; use crate::ty::{self, Ty, TyCtxt}; -use crate::util::captures::Captures; +use rustc_data_structures::captures::Captures; use rustc_hir::def_id::DefId; /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 37761c17f5243..cf424ffe7b293 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -100,7 +100,6 @@ pub mod ty; pub mod util { pub mod bug; - pub mod captures; pub mod common; } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 747e6e8da99af..518c0c75a3b51 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -26,8 +26,8 @@ use crate::ty::layout::VariantIdx; use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; use crate::ty::util::{Discr, IntTypeExt}; use crate::ty::walk::TypeWalker; -use crate::util::captures::Captures; use arena::SyncDroplessArena; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index aeda2eb1a15c0..c89d045cebb73 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -13,11 +13,10 @@ use crate::ty::layout::VariantIdx; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable}; use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS}; -use crate::util::captures::Captures; +use polonius_engine::Atom; +use rustc_data_structures::captures::Captures; use rustc_hir as hir; use rustc_hir::def_id::DefId; - -use polonius_engine::Atom; use rustc_index::vec::Idx; use rustc_macros::HashStable; use rustc_span::symbol::{kw, Symbol}; diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 062b093b8e68d..68f24f2396174 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -40,8 +40,10 @@ use rustc::hir::map::Map; use rustc::lint; use rustc::lint::builtin; use rustc::middle::cstore::CrateStore; -use rustc::util::captures::Captures; +use rustc::session::config::nightly_options; +use rustc::session::Session; use rustc::{bug, span_bug}; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_error_codes::*; diff --git a/src/librustc/util/captures.rs b/src/librustc_data_structures/captures.rs similarity index 100% rename from src/librustc/util/captures.rs rename to src/librustc_data_structures/captures.rs diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index d1b7ee9e83e76..51a38a7d2ab9c 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -67,6 +67,7 @@ macro_rules! unlikely { pub mod base_n; pub mod binary_search_util; pub mod box_region; +pub mod captures; pub mod const_cstr; pub mod flock; pub mod fx; diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 77d143643b59e..f5a05751f4c40 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -16,8 +16,8 @@ use rustc::mir::{self, interpret, BodyAndCache, Promoted}; use rustc::session::Session; use rustc::ty::codec::TyDecoder; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::util::captures::Captures; use rustc::util::common::record_time; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 03120e8009f0a..2bf1efd4441e9 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -229,6 +229,7 @@ use self::SliceKind::*; use self::Usefulness::*; use self::WitnessPreference::*; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::Idx; @@ -243,7 +244,6 @@ use rustc_hir::{HirId, RangeEnd}; use rustc::lint; use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; use rustc::mir::Field; -use rustc::util::captures::Captures; use rustc::util::common::ErrorReported; use rustc_span::{Span, DUMMY_SP}; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f10edc1a468b4..8ff9bdf22bb3b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -114,6 +114,7 @@ use rustc::ty::{ self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType, }; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -146,7 +147,6 @@ use crate::lint; use crate::require_c_abi_if_c_variadic; use crate::session::config::EntryFnType; use crate::session::Session; -use crate::util::captures::Captures; use crate::util::common::{indenter, ErrorReported}; use crate::TypeAndSubsts; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 84f2e186eaa35..3ec09e5f19af5 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -32,7 +32,7 @@ use rustc::ty::util::Discr; use rustc::ty::util::IntTypeExt; use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::{ReprOptions, ToPredicate}; -use rustc::util::captures::Captures; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; From 402907f27390edd0d6c8b73c3521f18a1e2c76d5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 6 Jan 2020 07:05:04 +0100 Subject: [PATCH 26/48] lowering: rustc::session -> rustc_session --- src/librustc_ast_lowering/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 68f24f2396174..f5d051618e2df 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -40,8 +40,6 @@ use rustc::hir::map::Map; use rustc::lint; use rustc::lint::builtin; use rustc::middle::cstore::CrateStore; -use rustc::session::config::nightly_options; -use rustc::session::Session; use rustc::{bug, span_bug}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; From 7472f9ef134465c8d077269236f09e8ef5767772 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 6 Jan 2020 07:34:52 +0100 Subject: [PATCH 27/48] lowering: remove dep on CrateStore --- src/librustc_ast_lowering/lib.rs | 13 +++---------- src/librustc_ast_lowering/path.rs | 8 +++----- src/librustc_resolve/lib.rs | 10 +++++++--- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index f5d051618e2df..d2a51c5d9cc22 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -39,7 +39,6 @@ use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions}; use rustc::hir::map::Map; use rustc::lint; use rustc::lint::builtin; -use rustc::middle::cstore::CrateStore; use rustc::{bug, span_bug}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; @@ -172,7 +171,9 @@ struct LoweringContext<'a, 'hir: 'a> { } pub trait Resolver { - fn cstore(&self) -> &dyn CrateStore; + fn def_key(&mut self, id: DefId) -> DefKey; + + fn item_generics_cloned_untracked_liftimes(&self, def: DefId, sess: &Session) -> usize; /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&mut self, id: NodeId) -> Option; @@ -936,14 +937,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ret } - fn def_key(&mut self, id: DefId) -> DefKey { - if id.is_local() { - self.resolver.definitions().def_key(id.index) - } else { - self.resolver.cstore().def_key(id) - } - } - fn lower_attrs(&mut self, attrs: &[Attribute]) -> &'hir [Attribute] { self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a))) } diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs index 4f71910b0bfe2..b4c196a254e4c 100644 --- a/src/librustc_ast_lowering/path.rs +++ b/src/librustc_ast_lowering/path.rs @@ -49,7 +49,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // which may need lifetime elision performed. let parent_def_id = |this: &mut Self, def_id: DefId| DefId { krate: def_id.krate, - index: this.def_key(def_id).parent.expect("missing parent"), + index: this.resolver.def_key(def_id).parent.expect("missing parent"), }; let type_def_id = match partial_res.base_res() { Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => { @@ -93,11 +93,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return n; } assert!(!def_id.is_local()); - let item_generics = self + let n = self .resolver - .cstore() - .item_generics_cloned_untracked(def_id, self.sess); - let n = item_generics.own_counts().lifetimes; + .item_generics_cloned_untracked_liftimes(def_id, self.sess); self.type_def_lifetime_params.insert(def_id, n); n }); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f8e42724df72b..8a6248aba866a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -22,7 +22,7 @@ use Determinacy::*; use errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc::hir::exports::ExportMap; -use rustc::hir::map::Definitions; +use rustc::hir::map::{DefKey, Definitions}; use rustc::lint; use rustc::middle::cstore::{CrateStore, MetadataLoaderDyn}; use rustc::session::Session; @@ -1027,8 +1027,12 @@ impl<'a, 'b> DefIdTree for &'a Resolver<'b> { /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that /// the resolver is no longer needed as all the relevant information is inline. impl rustc_ast_lowering::Resolver for Resolver<'_> { - fn cstore(&self) -> &dyn CrateStore { - self.cstore() + fn def_key(&mut self, id: DefId) -> DefKey { + if id.is_local() { self.definitions().def_key(id.index) } else { self.cstore().def_key(id) } + } + + fn item_generics_cloned_untracked_liftimes(&self, def_id: DefId, sess: &Session) -> usize { + self.cstore().item_generics_cloned_untracked(def_id, sess).own_counts().lifetimes } fn resolve_str_path( From b743af6a241edbe8700ce084000f4d3cf7c1182e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 8 Jan 2020 23:16:58 +0100 Subject: [PATCH 28/48] rename a method in Resolver trait --- src/librustc_ast_lowering/lib.rs | 2 +- src/librustc_ast_lowering/path.rs | 4 +--- src/librustc_resolve/lib.rs | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index d2a51c5d9cc22..2064a3c92f22c 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -173,7 +173,7 @@ struct LoweringContext<'a, 'hir: 'a> { pub trait Resolver { fn def_key(&mut self, id: DefId) -> DefKey; - fn item_generics_cloned_untracked_liftimes(&self, def: DefId, sess: &Session) -> usize; + fn item_generics_num_liftimes(&self, def: DefId, sess: &Session) -> usize; /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&mut self, id: NodeId) -> Option; diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs index b4c196a254e4c..f6b33de83a2b9 100644 --- a/src/librustc_ast_lowering/path.rs +++ b/src/librustc_ast_lowering/path.rs @@ -93,9 +93,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return n; } assert!(!def_id.is_local()); - let n = self - .resolver - .item_generics_cloned_untracked_liftimes(def_id, self.sess); + let n = self.resolver.item_generics_num_liftimes(def_id, self.sess); self.type_def_lifetime_params.insert(def_id, n); n }); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8a6248aba866a..0a4011fe3f404 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1031,7 +1031,7 @@ impl rustc_ast_lowering::Resolver for Resolver<'_> { if id.is_local() { self.definitions().def_key(id.index) } else { self.cstore().def_key(id) } } - fn item_generics_cloned_untracked_liftimes(&self, def_id: DefId, sess: &Session) -> usize { + fn item_generics_num_liftimes(&self, def_id: DefId, sess: &Session) -> usize { self.cstore().item_generics_cloned_untracked(def_id, sess).own_counts().lifetimes } From 5dafa6a46466ab26b7cd7c38f965d37af045af5d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 09:23:44 +0100 Subject: [PATCH 29/48] add CStore::item_generics_num_lifetimes --- src/librustc/middle/cstore.rs | 5 ++--- src/librustc_ast_lowering/lib.rs | 2 +- src/librustc_ast_lowering/path.rs | 2 +- src/librustc_metadata/creader.rs | 3 +-- src/librustc_metadata/rmeta/decoder/cstore_impl.rs | 8 ++++---- src/librustc_resolve/lib.rs | 4 ++-- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index ee43c35c1d05b..5b1e7673629b1 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -5,8 +5,8 @@ use crate::hir::map as hir_map; use crate::hir::map::definitions::{DefKey, DefPathTable}; use crate::session::search_paths::PathKind; -use crate::session::{CrateDisambiguator, Session}; -use crate::ty::{self, TyCtxt}; +use crate::session::CrateDisambiguator; +use crate::ty::TyCtxt; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{self, MetadataRef}; @@ -208,7 +208,6 @@ pub trait CrateStore { fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool; fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator; fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh; - fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics; // This is basically a 1-based range of ints, which is a little // silly - I may fix that. diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 2064a3c92f22c..0edc51f1aa4ec 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -173,7 +173,7 @@ struct LoweringContext<'a, 'hir: 'a> { pub trait Resolver { fn def_key(&mut self, id: DefId) -> DefKey; - fn item_generics_num_liftimes(&self, def: DefId, sess: &Session) -> usize; + fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize; /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&mut self, id: NodeId) -> Option; diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs index f6b33de83a2b9..9b504704ae06c 100644 --- a/src/librustc_ast_lowering/path.rs +++ b/src/librustc_ast_lowering/path.rs @@ -93,7 +93,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return n; } assert!(!def_id.is_local()); - let n = self.resolver.item_generics_num_liftimes(def_id, self.sess); + let n = self.resolver.item_generics_num_lifetimes(def_id, self.sess); self.type_def_lifetime_params.insert(def_id, n); n }); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index b21715fadfe6f..30d049d143eab 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -12,8 +12,7 @@ use rustc::session::{CrateDisambiguator, Session}; use rustc::ty::TyCtxt; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; -use rustc_hir::def_id::CrateNum; -use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_index::vec::IndexVec; use rustc_target::spec::{PanicStrategy, TargetTriple}; diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index ba3c4e4aff443..eb5754bf99bfb 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -478,6 +478,10 @@ impl CStore { pub fn crate_source_untracked(&self, cnum: CrateNum) -> CrateSource { self.get_crate_data(cnum).source.clone() } + + pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize { + self.get_crate_data(def_id.krate).get_generics(def_id.index, sess).own_counts().lifetimes + } } impl CrateStore for CStore { @@ -485,10 +489,6 @@ impl CrateStore for CStore { self } - fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics { - self.get_crate_data(def.krate).get_generics(def.index, sess) - } - fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol { self.get_crate_data(cnum).root.name } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0a4011fe3f404..9e4486e16f2cc 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1031,8 +1031,8 @@ impl rustc_ast_lowering::Resolver for Resolver<'_> { if id.is_local() { self.definitions().def_key(id.index) } else { self.cstore().def_key(id) } } - fn item_generics_num_liftimes(&self, def_id: DefId, sess: &Session) -> usize { - self.cstore().item_generics_cloned_untracked(def_id, sess).own_counts().lifetimes + fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize { + self.cstore().item_generics_num_lifetimes(def_id, sess) } fn resolve_str_path( From e632940a41fe6d65bd677da85d87046dc5da5022 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 9 Jan 2020 10:56:05 +0100 Subject: [PATCH 30/48] Update src/librustc_mir/interpret/place.rs Co-Authored-By: Ralf Jung --- src/librustc_mir/interpret/place.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 6428caa8fb0ed..87bb4c04b73ac 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -182,6 +182,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { pub fn dangling(layout: TyLayout<'tcx>, cx: &impl HasDataLayout) -> Self { let align = layout.align.abi; let ptr = Scalar::from_uint(align.bytes(), cx.pointer_size()); + // `Poison` this to make sure that the pointer value `ptr` is never observable by the program. MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout } } From a4fa5bb6a0396b54a4519a20cd61c321905b5ac2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 9 Jan 2020 12:02:44 +0100 Subject: [PATCH 31/48] Rename `Unsized` to `Meta` --- src/librustc_mir/interpret/eval_context.rs | 6 ++--- src/librustc_mir/interpret/intern.rs | 4 ++-- src/librustc_mir/interpret/place.rs | 28 +++++++++++----------- src/librustc_mir/interpret/snapshot.rs | 2 +- src/librustc_mir/interpret/validity.rs | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c5c2a6769e44a..864f4f9487c88 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -465,13 +465,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(Some((size, align))) } ty::Dynamic(..) => { - let vtable = metadata.unwrap_unsized(); + let vtable = metadata.unwrap_meta(); // Read size and align from vtable (already checks size). Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) } ty::Slice(_) | ty::Str => { - let len = metadata.unwrap_unsized().to_machine_usize(self)?; + let len = metadata.unwrap_meta().to_machine_usize(self)?; let elem = layout.field(self, 0)?; // Make sure the slice is not too big. @@ -817,7 +817,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { " by align({}){} ref:", mplace.align.bytes(), match mplace.meta { - MemPlaceMeta::Unsized(meta) => format!(" meta({:?})", meta), + MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta), MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(), } ) diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 56e489d0bd590..9b3a2fa36f794 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -193,7 +193,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx { // Validation has already errored on an invalid vtable pointer so we can safely not // do anything if this is not a real pointer. - if let Scalar::Ptr(vtable) = mplace.meta.unwrap_unsized() { + if let Scalar::Ptr(vtable) = mplace.meta.unwrap_meta() { // Explicitly choose `Immutable` here, since vtables are immutable, even // if the reference of the fat pointer is mutable. self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; @@ -227,7 +227,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx ty::Array(_, n) if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {} ty::Slice(_) - if mplace.meta.unwrap_unsized().to_machine_usize(self.ecx)? == 0 => {} + if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? == 0 => {} _ => bug!("const qualif failed to prevent mutable references"), }, } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 87bb4c04b73ac..890627a54543a 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -24,7 +24,7 @@ use super::{ /// Information required for the sound usage of a `MemPlace`. pub enum MemPlaceMeta { /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). - Unsized(Scalar), + Meta(Scalar), /// `Sized` types or unsized `extern type` None, /// The address of this place may not be taken. This protects the `MemPlace` from coming from @@ -35,17 +35,17 @@ pub enum MemPlaceMeta { } impl MemPlaceMeta { - pub fn unwrap_unsized(self) -> Scalar { + pub fn unwrap_meta(self) -> Scalar { match self { - Self::Unsized(s) => s, + Self::Meta(s) => s, Self::None | Self::Poison => { bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)") } } } - fn is_unsized(self) -> bool { + fn has_meta(self) -> bool { match self { - Self::Unsized(_) => true, + Self::Meta(_) => true, Self::None | Self::Poison => false, } } @@ -54,7 +54,7 @@ impl MemPlaceMeta { impl MemPlaceMeta { pub fn erase_tag(self) -> MemPlaceMeta<()> { match self { - Self::Unsized(s) => MemPlaceMeta::Unsized(s.erase_tag()), + Self::Meta(s) => MemPlaceMeta::Meta(s.erase_tag()), Self::None => MemPlaceMeta::None, Self::Poison => MemPlaceMeta::Poison, } @@ -154,7 +154,7 @@ impl MemPlace { pub fn to_ref(self) -> Immediate { match self.meta { MemPlaceMeta::None => Immediate::Scalar(self.ptr.into()), - MemPlaceMeta::Unsized(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()), + MemPlaceMeta::Meta(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()), MemPlaceMeta::Poison => bug!( "MPlaceTy::dangling may never be used to produce a \ place that will have the address of its pointee taken" @@ -214,7 +214,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { // We need to consult `meta` metadata match self.layout.ty.kind { ty::Slice(..) | ty::Str => { - return self.mplace.meta.unwrap_unsized().to_machine_usize(cx); + return self.mplace.meta.unwrap_meta().to_machine_usize(cx); } _ => bug!("len not supported on unsized type {:?}", self.layout.ty), } @@ -231,7 +231,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { #[inline] pub(super) fn vtable(self) -> Scalar { match self.layout.ty.kind { - ty::Dynamic(..) => self.mplace.meta.unwrap_unsized(), + ty::Dynamic(..) => self.mplace.meta.unwrap_meta(), _ => bug!("vtable not supported on type {:?}", self.layout.ty), } } @@ -312,7 +312,7 @@ where let (ptr, meta) = match *val { Immediate::Scalar(ptr) => (ptr.not_undef()?, MemPlaceMeta::None), Immediate::ScalarPair(ptr, meta) => { - (ptr.not_undef()?, MemPlaceMeta::Unsized(meta.not_undef()?)) + (ptr.not_undef()?, MemPlaceMeta::Meta(meta.not_undef()?)) } }; @@ -354,7 +354,7 @@ where ) -> InterpResult<'tcx, Option>> { let size = size.unwrap_or_else(|| { assert!(!place.layout.is_unsized()); - assert!(!place.meta.is_unsized()); + assert!(!place.meta.has_meta()); place.layout.size }); self.memory.check_ptr_access(place.ptr, size, place.align) @@ -505,7 +505,7 @@ where ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)), ty::Slice(..) => { let len = Scalar::from_uint(inner_len, self.pointer_size()); - (MemPlaceMeta::Unsized(len), base.layout.ty) + (MemPlaceMeta::Meta(len), base.layout.ty) } _ => bug!("cannot subslice non-array type: `{:?}`", base.layout.ty), }; @@ -519,7 +519,7 @@ where variant: VariantIdx, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // Downcasts only change the layout - assert!(!base.meta.is_unsized()); + assert!(!base.meta.has_meta()); Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base }) } @@ -1081,7 +1081,7 @@ where let mplace = MemPlace { ptr: ptr.into(), align: Align::from_bytes(1).unwrap(), - meta: MemPlaceMeta::Unsized(meta), + meta: MemPlaceMeta::Meta(meta), }; let layout = self.layout_of(self.tcx.mk_static_str()).unwrap(); diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 120baaf3be68a..a8e67c8f208a9 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -209,7 +209,7 @@ impl_snapshot_for!( impl_snapshot_for!( enum MemPlaceMeta { - Unsized(s), + Meta(s), None, Poison, } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 7a7f431402075..12e8cb6071d92 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -252,7 +252,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); match tail.kind { ty::Dynamic(..) => { - let vtable = meta.unwrap_unsized(); + let vtable = meta.unwrap_meta(); try_validation!( self.ecx.memory.check_ptr_access( vtable, @@ -276,7 +276,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M } ty::Slice(..) | ty::Str => { let _len = try_validation!( - meta.unwrap_unsized().to_machine_usize(self.ecx), + meta.unwrap_meta().to_machine_usize(self.ecx), "non-integer slice length in wide pointer", self.path ); From c5c4fa8e7633c28464e3b27a57f2f175cc6700fd Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 9 Jan 2020 12:03:37 +0100 Subject: [PATCH 32/48] Switch assertion order to be more helpful to ppl that encounter them --- src/librustc_mir/const_eval/eval_queries.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index d2a0798249ad9..53f3b539bdaa0 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -124,13 +124,13 @@ pub(super) fn op_to_const<'tcx>( ConstValue::ByRef { alloc, offset: ptr.offset } } Scalar::Raw { data, .. } => { + assert!(mplace.layout.is_zst()); assert_eq!( data, mplace.layout.align.abi.bytes().into(), "this MPlaceTy must come from `try_as_mplace` being used on a zst, so we know what value this integer address must have", ); - assert!(mplace.layout.is_zst()); ConstValue::Scalar(Scalar::zst()) } }; From 915db7ae6430baef99f186ba40f08e105b7694fe Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 23:00:28 +0100 Subject: [PATCH 33/48] expect `fn` after `const unsafe` / `const extern` --- src/librustc_parse/parser/item.rs | 2 +- ...onst-extern-fns-dont-need-fn-specifier-2.rs | 7 +++++++ ...-extern-fns-dont-need-fn-specifier-2.stderr | 8 ++++++++ ...-const-extern-fns-dont-need-fn-specifier.rs | 8 ++++++++ ...st-extern-fns-dont-need-fn-specifier.stderr | 18 ++++++++++++++++++ 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs create mode 100644 src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr create mode 100644 src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs create mode 100644 src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 918e826fc26bf..866bd1ccb55be 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -140,7 +140,7 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span)); } let ext = self.parse_extern()?; - self.bump(); // `fn` + self.expect_keyword(kw::Fn)?; let header = FnHeader { unsafety, diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs new file mode 100644 index 0000000000000..7ced24808bf6e --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs @@ -0,0 +1,7 @@ +fn main() {} + +#[cfg(FALSE)] +fn container() { + const unsafe WhereIsFerris Now() {} + //~^ ERROR expected one of `extern` or `fn` +} diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr new file mode 100644 index 0000000000000..5ec9e2a91f1dc --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr @@ -0,0 +1,8 @@ +error: expected one of `extern` or `fn`, found `WhereIsFerris` + --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs:5:18 + | +LL | const unsafe WhereIsFerris Now() {} + | ^^^^^^^^^^^^^ expected one of `extern` or `fn` + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs new file mode 100644 index 0000000000000..1886bfccb4e3e --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs @@ -0,0 +1,8 @@ +fn main() {} + +#[cfg(FALSE)] +fn container() { + const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } + //~^ ERROR expected `fn` + //~| ERROR `const extern fn` definitions are unstable +} diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr new file mode 100644 index 0000000000000..cf71ed4d59765 --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr @@ -0,0 +1,18 @@ +error: expected `fn`, found `PUT_ANYTHING_YOU_WANT_HERE` + --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:25 + | +LL | const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `fn` + +error[E0658]: `const extern fn` definitions are unstable + --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:5 + | +LL | const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } + | ^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/64926 + = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From c751961d290e4da3caae3d5f1d01435accea6c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 9 Jan 2020 13:46:37 -0800 Subject: [PATCH 34/48] Extend support of `_` in type parameters - Account for `impl Trait<_>`. - Provide a reasonable `Span` for empty `Generics` in `impl`s. - Account for `fn foo<_>(_: _) {}` to suggest `fn foo(_: T) {}`. - Fix #67995. --- src/librustc_parse/parser/generics.rs | 2 +- src/librustc_parse/parser/item.rs | 6 ++- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/collect.rs | 36 +++++++++++---- .../ui/typeck/typeck_type_placeholder_item.rs | 13 ++++++ .../typeck_type_placeholder_item.stderr | 44 ++++++++++++++++++- 6 files changed, 91 insertions(+), 12 deletions(-) diff --git a/src/librustc_parse/parser/generics.rs b/src/librustc_parse/parser/generics.rs index 1b816e2b90da9..075583711f5d3 100644 --- a/src/librustc_parse/parser/generics.rs +++ b/src/librustc_parse/parser/generics.rs @@ -156,7 +156,7 @@ impl<'a> Parser<'a> { self.expect_gt()?; (params, span_lo.to(self.prev_span)) } else { - (vec![], self.prev_span.between(self.token.span)) + (vec![], self.prev_span.shrink_to_hi()) }; Ok(ast::Generics { params, diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 918e826fc26bf..12dcf0391da1e 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -555,7 +555,11 @@ impl<'a> Parser<'a> { let mut generics = if self.choose_generics_over_qpath() { self.parse_generics()? } else { - Generics::default() + let mut generics = Generics::default(); + // impl A for B {} + // /\ this is where `generics.span` should point when there are no type params. + generics.span = self.prev_span.shrink_to_hi(); + generics }; // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 4bacf9349379e..2b27138a4d854 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -2803,7 +2803,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // allowed. `allow_ty_infer` gates this behavior. crate::collect::placeholder_type_error( tcx, - ident_span.unwrap_or(DUMMY_SP), + ident_span.map(|sp| sp.shrink_to_hi()).unwrap_or(DUMMY_SP), generic_params, visitor.0, ident_span.is_some(), diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 35c380612d2fb..43a2bcd564f4c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -124,7 +124,7 @@ struct CollectItemTypesVisitor<'tcx> { /// all already existing generic type parameters to avoid suggesting a name that is already in use. crate fn placeholder_type_error( tcx: TyCtxt<'tcx>, - ident_span: Span, + span: Span, generics: &[hir::GenericParam<'_>], placeholder_types: Vec, suggest: bool, @@ -150,7 +150,14 @@ crate fn placeholder_type_error( let mut sugg: Vec<_> = placeholder_types.iter().map(|sp| (*sp, type_name.to_string())).collect(); if generics.is_empty() { - sugg.push((ident_span.shrink_to_hi(), format!("<{}>", type_name))); + sugg.push((span, format!("<{}>", type_name))); + } else if let Some(arg) = generics.iter().find(|arg| match arg.name { + hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true, + _ => false, + }) { + // Account for `_` already present in cases like `struct S<_>(_);` and suggest + // `struct S(T);` instead of `struct S<_, T>(T);`. + sugg.push((arg.span, format!("{}", type_name))); } else { sugg.push(( generics.iter().last().unwrap().span.shrink_to_hi(), @@ -172,8 +179,12 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir let (generics, suggest) = match &item.kind { hir::ItemKind::Union(_, generics) | hir::ItemKind::Enum(_, generics) - | hir::ItemKind::Struct(_, generics) => (&generics.params[..], true), - hir::ItemKind::TyAlias(_, generics) => (&generics.params[..], false), + | hir::ItemKind::TraitAlias(generics, _) + | hir::ItemKind::Trait(_, _, generics, ..) + | hir::ItemKind::Impl(_, _, _, generics, ..) + | hir::ItemKind::Struct(_, generics) => (generics, true), + hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }) + | hir::ItemKind::TyAlias(_, generics) => (generics, false), // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type. _ => return, }; @@ -181,7 +192,7 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_item(item); - placeholder_type_error(tcx, item.ident.span, generics, visitor.0, suggest); + placeholder_type_error(tcx, generics.span, &generics.params[..], visitor.0, suggest); } impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { @@ -1789,10 +1800,19 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { /// Whether `ty` is a type with `_` placeholders that can be infered. Used in diagnostics only to /// use inference to provide suggestions for the appropriate type if possible. fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool { + use hir::TyKind::*; match &ty.kind { - hir::TyKind::Infer => true, - hir::TyKind::Slice(ty) | hir::TyKind::Array(ty, _) => is_suggestable_infer_ty(ty), - hir::TyKind::Tup(tys) => tys.iter().any(|ty| is_suggestable_infer_ty(ty)), + Infer => true, + Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty), + Tup(tys) => tys.iter().any(is_suggestable_infer_ty), + Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty), + Def(_, generic_args) => generic_args + .iter() + .filter_map(|arg| match arg { + hir::GenericArg::Type(ty) => Some(ty), + _ => None, + }) + .any(is_suggestable_infer_ty), _ => false, } } diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs index 5b0ca2f347ea8..a53042d6e9538 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs @@ -131,3 +131,16 @@ trait T { fn assoc_fn_test3() -> _; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures } + +struct BadStruct<_>(_); +//~^ ERROR expected identifier, found reserved identifier `_` +//~| ERROR the type placeholder `_` is not allowed within types on item signatures +trait BadTrait<_> {} +//~^ ERROR expected identifier, found reserved identifier `_` +impl BadTrait<_> for BadStruct<_> {} +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures + +fn impl_trait() -> impl BadTrait<_> { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures + unimplemented!() +} diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index 9fe7af4c822c1..e788bf37790cf 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -1,3 +1,15 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/typeck_type_placeholder_item.rs:135:18 + | +LL | struct BadStruct<_>(_); + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/typeck_type_placeholder_item.rs:138:16 + | +LL | trait BadTrait<_> {} + | ^ expected identifier, found reserved identifier + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:4:14 | @@ -255,6 +267,36 @@ LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | | not allowed in type signatures | help: replace with the correct return type: `(i32, i32)` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:135:21 + | +LL | struct BadStruct<_>(_); + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | struct BadStruct(T); + | ^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:140:15 + | +LL | impl BadTrait<_> for BadStruct<_> {} + | ^ ^ not allowed in type signatures + | | + | not allowed in type signatures + | +help: use type parameters instead + | +LL | impl BadTrait for BadStruct {} + | ^^^ ^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:143:34 + | +LL | fn impl_trait() -> impl BadTrait<_> { + | ^ not allowed in type signatures + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:121:31 | @@ -405,7 +447,7 @@ help: use type parameters instead LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } | ^^^ ^ -error: aborting due to 40 previous errors +error: aborting due to 45 previous errors Some errors have detailed explanations: E0121, E0282. For more information about an error, try `rustc --explain E0121`. From 6e04cf062f605fbd70d728dcd364ad3eac0f822c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 9 Jan 2020 14:53:17 -0800 Subject: [PATCH 35/48] review comments: more tests --- .../ui/typeck/typeck_type_placeholder_item.rs | 32 +++ .../typeck_type_placeholder_item.stderr | 248 ++++++++++++------ 2 files changed, 195 insertions(+), 85 deletions(-) diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs index a53042d6e9538..adecbd7e5b40e 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs @@ -1,3 +1,4 @@ +#![feature(type_alias_impl_trait)] // Needed for single test `type Y = impl Trait<_>` // This test checks that it is not possible to enable global type // inference by using the `_` type placeholder. @@ -42,6 +43,16 @@ impl Test9 { //~^ ERROR the type placeholder `_` is not allowed within types on item signatures } +fn test11(x: &usize) -> &_ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures + &x +} + +unsafe fn test12(x: *const usize) -> *const *const _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures + &x +} + impl Clone for Test9 { fn clone(&self) -> _ { Test9 } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures @@ -144,3 +155,24 @@ fn impl_trait() -> impl BadTrait<_> { //~^ ERROR the type placeholder `_` is not allowed within types on item signatures unimplemented!() } + +struct BadStruct1<_, _>(_); +//~^ ERROR expected identifier, found reserved identifier `_` +//~| ERROR expected identifier, found reserved identifier `_` +//~| ERROR the name `_` is already used +//~| ERROR the type placeholder `_` is not allowed within types on item signatures +struct BadStruct2<_, T>(_, T); +//~^ ERROR expected identifier, found reserved identifier `_` +//~| ERROR the type placeholder `_` is not allowed within types on item signatures + +type X = Box<_>; +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures + +struct Struct; +trait Trait {} +impl Trait for Struct {} +type Y = impl Trait<_>; +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures +fn foo() -> Y { + Struct +} diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index e788bf37790cf..05326a3e07a93 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -1,17 +1,43 @@ error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:135:18 + --> $DIR/typeck_type_placeholder_item.rs:146:18 | LL | struct BadStruct<_>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:138:16 + --> $DIR/typeck_type_placeholder_item.rs:149:16 | LL | trait BadTrait<_> {} | ^ expected identifier, found reserved identifier +error: expected identifier, found reserved identifier `_` + --> $DIR/typeck_type_placeholder_item.rs:159:19 + | +LL | struct BadStruct1<_, _>(_); + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/typeck_type_placeholder_item.rs:159:22 + | +LL | struct BadStruct1<_, _>(_); + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/typeck_type_placeholder_item.rs:164:19 + | +LL | struct BadStruct2<_, T>(_, T); + | ^ expected identifier, found reserved identifier + +error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters + --> $DIR/typeck_type_placeholder_item.rs:159:22 + | +LL | struct BadStruct1<_, _>(_); + | - ^ already used + | | + | first use of `_` + error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:4:14 + --> $DIR/typeck_type_placeholder_item.rs:5:14 | LL | fn test() -> _ { 5 } | ^ @@ -20,7 +46,7 @@ LL | fn test() -> _ { 5 } | help: replace with the correct return type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:7:16 + --> $DIR/typeck_type_placeholder_item.rs:8:16 | LL | fn test2() -> (_, _) { (5, 5) } | -^--^- @@ -30,7 +56,7 @@ LL | fn test2() -> (_, _) { (5, 5) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:10:15 + --> $DIR/typeck_type_placeholder_item.rs:11:15 | LL | static TEST3: _ = "test"; | ^ @@ -39,7 +65,7 @@ LL | static TEST3: _ = "test"; | help: replace `_` with the correct type: `&'static str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:13:15 + --> $DIR/typeck_type_placeholder_item.rs:14:15 | LL | static TEST4: _ = 145; | ^ @@ -48,13 +74,13 @@ LL | static TEST4: _ = 145; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:16:15 + --> $DIR/typeck_type_placeholder_item.rs:17:15 | LL | static TEST5: (_, _) = (1, 2); | ^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:19:13 + --> $DIR/typeck_type_placeholder_item.rs:20:13 | LL | fn test6(_: _) { } | ^ not allowed in type signatures @@ -65,7 +91,7 @@ LL | fn test6(_: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:22:18 + --> $DIR/typeck_type_placeholder_item.rs:23:18 | LL | fn test6_b(_: _, _: T) { } | ^ not allowed in type signatures @@ -76,7 +102,7 @@ LL | fn test6_b(_: K, _: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:25:30 + --> $DIR/typeck_type_placeholder_item.rs:26:30 | LL | fn test6_c(_: _, _: (T, K, L, A, B)) { } | ^ not allowed in type signatures @@ -87,7 +113,7 @@ LL | fn test6_c(_: C, _: (T, K, L, A, B)) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:28:13 + --> $DIR/typeck_type_placeholder_item.rs:29:13 | LL | fn test7(x: _) { let _x: usize = x; } | ^ not allowed in type signatures @@ -98,13 +124,13 @@ LL | fn test7(x: T) { let _x: usize = x; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:31:22 + --> $DIR/typeck_type_placeholder_item.rs:32:22 | LL | fn test8(_f: fn() -> _) { } | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:31:22 + --> $DIR/typeck_type_placeholder_item.rs:32:22 | LL | fn test8(_f: fn() -> _) { } | ^ not allowed in type signatures @@ -115,7 +141,25 @@ LL | fn test8(_f: fn() -> T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:54:8 + --> $DIR/typeck_type_placeholder_item.rs:46:26 + | +LL | fn test11(x: &usize) -> &_ { + | -^ + | || + | |not allowed in type signatures + | help: replace with the correct return type: `&&usize` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:51:52 + | +LL | unsafe fn test12(x: *const usize) -> *const *const _ { + | --------------^ + | | | + | | not allowed in type signatures + | help: replace with the correct return type: `*const *const usize` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:65:8 | LL | a: _, | ^ not allowed in type signatures @@ -134,7 +178,7 @@ LL | b: (T, T), | error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:60:21 + --> $DIR/typeck_type_placeholder_item.rs:71:21 | LL | fn fn_test() -> _ { 5 } | ^ @@ -143,7 +187,7 @@ LL | fn fn_test() -> _ { 5 } | help: replace with the correct return type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:63:23 + --> $DIR/typeck_type_placeholder_item.rs:74:23 | LL | fn fn_test2() -> (_, _) { (5, 5) } | -^--^- @@ -153,7 +197,7 @@ LL | fn fn_test2() -> (_, _) { (5, 5) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:66:22 + --> $DIR/typeck_type_placeholder_item.rs:77:22 | LL | static FN_TEST3: _ = "test"; | ^ @@ -162,7 +206,7 @@ LL | static FN_TEST3: _ = "test"; | help: replace `_` with the correct type: `&'static str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:69:22 + --> $DIR/typeck_type_placeholder_item.rs:80:22 | LL | static FN_TEST4: _ = 145; | ^ @@ -171,13 +215,13 @@ LL | static FN_TEST4: _ = 145; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:72:22 + --> $DIR/typeck_type_placeholder_item.rs:83:22 | LL | static FN_TEST5: (_, _) = (1, 2); | ^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:75:20 + --> $DIR/typeck_type_placeholder_item.rs:86:20 | LL | fn fn_test6(_: _) { } | ^ not allowed in type signatures @@ -188,7 +232,7 @@ LL | fn fn_test6(_: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:78:20 + --> $DIR/typeck_type_placeholder_item.rs:89:20 | LL | fn fn_test7(x: _) { let _x: usize = x; } | ^ not allowed in type signatures @@ -199,13 +243,13 @@ LL | fn fn_test7(x: T) { let _x: usize = x; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:81:29 + --> $DIR/typeck_type_placeholder_item.rs:92:29 | LL | fn fn_test8(_f: fn() -> _) { } | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:81:29 + --> $DIR/typeck_type_placeholder_item.rs:92:29 | LL | fn fn_test8(_f: fn() -> _) { } | ^ not allowed in type signatures @@ -216,7 +260,7 @@ LL | fn fn_test8(_f: fn() -> T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:104:12 + --> $DIR/typeck_type_placeholder_item.rs:115:12 | LL | a: _, | ^ not allowed in type signatures @@ -235,13 +279,13 @@ LL | b: (T, T), | error[E0282]: type annotations needed - --> $DIR/typeck_type_placeholder_item.rs:109:27 + --> $DIR/typeck_type_placeholder_item.rs:120:27 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^^^^^^ cannot infer type error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:109:28 + --> $DIR/typeck_type_placeholder_item.rs:120:28 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^ ^ not allowed in type signatures @@ -249,7 +293,7 @@ LL | fn fn_test11(_: _) -> (_, _) { panic!() } | not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:113:30 + --> $DIR/typeck_type_placeholder_item.rs:124:30 | LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | -^--^- @@ -259,7 +303,7 @@ LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:116:33 + --> $DIR/typeck_type_placeholder_item.rs:127:33 | LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | ------^- @@ -268,7 +312,7 @@ LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:135:21 + --> $DIR/typeck_type_placeholder_item.rs:146:21 | LL | struct BadStruct<_>(_); | ^ not allowed in type signatures @@ -279,7 +323,7 @@ LL | struct BadStruct(T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:140:15 + --> $DIR/typeck_type_placeholder_item.rs:151:15 | LL | impl BadTrait<_> for BadStruct<_> {} | ^ ^ not allowed in type signatures @@ -292,13 +336,52 @@ LL | impl BadTrait for BadStruct {} | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:143:34 + --> $DIR/typeck_type_placeholder_item.rs:154:34 | LL | fn impl_trait() -> impl BadTrait<_> { | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:121:31 + --> $DIR/typeck_type_placeholder_item.rs:159:25 + | +LL | struct BadStruct1<_, _>(_); + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | struct BadStruct1(T); + | ^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:164:25 + | +LL | struct BadStruct2<_, T>(_, T); + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | struct BadStruct2(K, T); + | ^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:168:14 + | +LL | type X = Box<_>; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:42:27 + | +LL | fn test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn test10(&self, _x : T) { } + | ^^^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:132:31 | LL | fn method_test1(&self, x: _); | ^ not allowed in type signatures @@ -309,7 +392,7 @@ LL | fn method_test1(&self, x: T); | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:123:31 + --> $DIR/typeck_type_placeholder_item.rs:134:31 | LL | fn method_test2(&self, x: _) -> _; | ^ ^ not allowed in type signatures @@ -322,7 +405,7 @@ LL | fn method_test2(&self, x: T) -> T; | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:125:31 + --> $DIR/typeck_type_placeholder_item.rs:136:31 | LL | fn method_test3(&self) -> _; | ^ not allowed in type signatures @@ -333,7 +416,7 @@ LL | fn method_test3(&self) -> T; | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:127:26 + --> $DIR/typeck_type_placeholder_item.rs:138:26 | LL | fn assoc_fn_test1(x: _); | ^ not allowed in type signatures @@ -344,7 +427,7 @@ LL | fn assoc_fn_test1(x: T); | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:129:26 + --> $DIR/typeck_type_placeholder_item.rs:140:26 | LL | fn assoc_fn_test2(x: _) -> _; | ^ ^ not allowed in type signatures @@ -357,7 +440,7 @@ LL | fn assoc_fn_test2(x: T) -> T; | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:131:28 + --> $DIR/typeck_type_placeholder_item.rs:142:28 | LL | fn assoc_fn_test3() -> _; | ^ not allowed in type signatures @@ -368,47 +451,64 @@ LL | fn assoc_fn_test3() -> T; | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:38:24 + --> $DIR/typeck_type_placeholder_item.rs:60:37 | -LL | fn test9(&self) -> _ { () } - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `()` +LL | fn clone_from(&mut self, other: _) { *self = Test9; } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn clone_from(&mut self, other: T) { *self = Test9; } + | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:41:27 + --> $DIR/typeck_type_placeholder_item.rs:102:34 | -LL | fn test10(&self, _x : _) { } - | ^ not allowed in type signatures +LL | fn fn_test10(&self, _x : _) { } + | ^ not allowed in type signatures | help: use type parameters instead | -LL | fn test10(&self, _x : T) { } - | ^^^ ^ +LL | fn fn_test10(&self, _x : T) { } + | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:46:24 + --> $DIR/typeck_type_placeholder_item.rs:110:41 | -LL | fn clone(&self) -> _ { Test9 } +LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } + | ^^^ ^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:174:21 + | +LL | type Y = impl Trait<_>; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:39:24 + | +LL | fn test9(&self) -> _ { () } | ^ | | | not allowed in type signatures - | help: replace with the correct return type: `Test9` + | help: replace with the correct return type: `()` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:49:37 - | -LL | fn clone_from(&mut self, other: _) { *self = Test9; } - | ^ not allowed in type signatures - | -help: use type parameters instead + --> $DIR/typeck_type_placeholder_item.rs:57:24 | -LL | fn clone_from(&mut self, other: T) { *self = Test9; } - | ^^^ ^ +LL | fn clone(&self) -> _ { Test9 } + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `Test9` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:88:31 + --> $DIR/typeck_type_placeholder_item.rs:99:31 | LL | fn fn_test9(&self) -> _ { () } | ^ @@ -417,18 +517,7 @@ LL | fn fn_test9(&self) -> _ { () } | help: replace with the correct return type: `()` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:91:34 - | -LL | fn fn_test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn fn_test10(&self, _x : T) { } - | ^^^ ^ - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:96:28 + --> $DIR/typeck_type_placeholder_item.rs:107:28 | LL | fn clone(&self) -> _ { FnTest9 } | ^ @@ -436,18 +525,7 @@ LL | fn clone(&self) -> _ { FnTest9 } | not allowed in type signatures | help: replace with the correct return type: `main::FnTest9` -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:99:41 - | -LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } - | ^^^ ^ - -error: aborting due to 45 previous errors +error: aborting due to 55 previous errors -Some errors have detailed explanations: E0121, E0282. +Some errors have detailed explanations: E0121, E0282, E0403. For more information about an error, try `rustc --explain E0121`. From 63e2e44eb94c375527ddc6438479a0dd10ed4310 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Jan 2020 15:45:48 -0800 Subject: [PATCH 36/48] Add `const_trait_impl` feature gate --- src/librustc_feature/active.rs | 4 ++++ src/librustc_span/symbol.rs | 1 + src/libsyntax/feature_gate/check.rs | 1 + 3 files changed, 6 insertions(+) diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 8cb1684491bb8..77ee9f40b6c71 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -544,6 +544,9 @@ declare_features! ( /// For example, you can write `x @ Some(y)`. (active, bindings_after_at, "1.41.0", Some(65490), None), + /// Allows `impl const Trait for T` syntax. + (active, const_trait_impl, "1.42.0", Some(67792), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -559,4 +562,5 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::or_patterns, sym::let_chains, sym::raw_dylib, + sym::const_trait_impl, ]; diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 40abc8b2179b8..5ba45e0a67399 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -219,6 +219,7 @@ symbols! { const_raw_ptr_deref, const_raw_ptr_to_usize_cast, const_transmute, + const_trait_impl, contents, context, convert, diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 26545bfa61b60..f5090bf15536d 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -909,6 +909,7 @@ pub fn check_crate( gate_all!(or_patterns, "or-patterns syntax is experimental"); gate_all!(const_extern_fn, "`const extern fn` definitions are unstable"); gate_all!(raw_ref_op, "raw address of syntax is experimental"); + gate_all!(const_trait_impl, "const trait impls are experimental"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). From 6fc41585043927c3b9b404ddc357e67ab443eb70 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Jan 2020 15:46:30 -0800 Subject: [PATCH 37/48] Add `const_trait_bound_opt_out` feature gate --- src/librustc_feature/active.rs | 4 ++++ src/librustc_span/symbol.rs | 1 + src/libsyntax/feature_gate/check.rs | 1 + 3 files changed, 6 insertions(+) diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 77ee9f40b6c71..6a15cc5cb0fce 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -547,6 +547,9 @@ declare_features! ( /// Allows `impl const Trait for T` syntax. (active, const_trait_impl, "1.42.0", Some(67792), None), + /// Allows `T: ?const Trait` syntax in bounds. + (active, const_trait_bound_opt_out, "1.42.0", Some(67794), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -563,4 +566,5 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::let_chains, sym::raw_dylib, sym::const_trait_impl, + sym::const_trait_bound_opt_out, ]; diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 5ba45e0a67399..d9f4b72560ceb 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -219,6 +219,7 @@ symbols! { const_raw_ptr_deref, const_raw_ptr_to_usize_cast, const_transmute, + const_trait_bound_opt_out, const_trait_impl, contents, context, diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index f5090bf15536d..52eb20d320f7b 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -909,6 +909,7 @@ pub fn check_crate( gate_all!(or_patterns, "or-patterns syntax is experimental"); gate_all!(const_extern_fn, "`const extern fn` definitions are unstable"); gate_all!(raw_ref_op, "raw address of syntax is experimental"); + gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental"); gate_all!(const_trait_impl, "const trait impls are experimental"); // All uses of `gate_all!` below this point were added in #65742, From fd4a6a12136c5b5d6bce4081e95890df1fd1febd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Jan 2020 15:47:27 -0800 Subject: [PATCH 38/48] Add a `constness` field to `ast::TraitRef` This is used for both the `?const` syntax in bounds as well as the `impl const Trait` syntax. I also considered handling these separately by adding a variant of `TraitBoundModifier` and a field to `ItemKind::Impl`, but this approach was less intrusive. --- src/librustc_expand/build.rs | 2 +- src/libsyntax/ast.rs | 20 +++++++++++++++++--- src/libsyntax/mut_visit.rs | 3 ++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index 11f94ab2e6279..bd3d6b589d00a 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -110,7 +110,7 @@ impl<'a> ExtCtxt<'a> { } pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef { - ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID } + ast::TraitRef { path, constness: None, ref_id: ast::DUMMY_NODE_ID } } pub fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 47070261385a2..1d3bb7d87686c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1033,7 +1033,7 @@ impl Expr { pub fn to_bound(&self) -> Option { match &self.kind { ExprKind::Path(None, path) => Some(GenericBound::Trait( - PolyTraitRef::new(Vec::new(), path.clone(), self.span), + PolyTraitRef::new(Vec::new(), path.clone(), None, self.span), TraitBoundModifier::None, )), _ => None, @@ -2376,6 +2376,15 @@ pub enum AttrKind { pub struct TraitRef { pub path: Path, pub ref_id: NodeId, + + /// The `const` modifier, if any, that appears before this trait. + /// + /// | | `constness` | + /// |----------------|-----------------------------| + /// | `Trait` | `None` | + /// | `const Trait` | `Some(Constness::Const)` | + /// | `?const Trait` | `Some(Constness::NotConst)` | + pub constness: Option, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -2390,10 +2399,15 @@ pub struct PolyTraitRef { } impl PolyTraitRef { - pub fn new(generic_params: Vec, path: Path, span: Span) -> Self { + pub fn new( + generic_params: Vec, + path: Path, + constness: Option, + span: Span, + ) -> Self { PolyTraitRef { bound_generic_params: generic_params, - trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID }, + trait_ref: TraitRef { path, constness, ref_id: DUMMY_NODE_ID }, span, } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 1413f1566d043..264ba25cedecc 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -838,7 +838,8 @@ pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut } } -pub fn noop_visit_trait_ref(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) { +pub fn noop_visit_trait_ref(tr: &mut TraitRef, vis: &mut T) { + let TraitRef { path, ref_id, constness: _ } = tr; vis.visit_path(path); vis.visit_id(ref_id); } From 1c3fe9de4e9b7c41cc0ba86696b4e58f9e0e36e4 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Jan 2020 15:49:45 -0800 Subject: [PATCH 39/48] Parse `impl const Trait for Ty` syntax --- src/librustc_parse/parser/item.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 918e826fc26bf..86ab8bf57a3e3 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -542,10 +542,11 @@ impl<'a> Parser<'a> { /// impl<'a, T> TYPE { /* impl items */ } /// impl<'a, T> TRAIT for TYPE { /* impl items */ } /// impl<'a, T> !TRAIT for TYPE { /* impl items */ } + /// impl<'a, T> const TRAIT for TYPE { /* impl items */ } /// /// We actually parse slightly more relaxed grammar for better error reporting and recovery. - /// `impl` GENERICS `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}` - /// `impl` GENERICS `!`? TYPE (`where` PREDICATES)? `{` BODY `}` + /// `impl` GENERICS `const`? `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}` + /// `impl` GENERICS `const`? `!`? TYPE (`where` PREDICATES)? `{` BODY `}` fn parse_item_impl( &mut self, unsafety: Unsafety, @@ -558,6 +559,13 @@ impl<'a> Parser<'a> { Generics::default() }; + let constness = if self.eat_keyword(kw::Const) { + self.sess.gated_spans.gate(sym::const_trait_impl, self.prev_span); + Some(Constness::Const) + } else { + None + }; + // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. let polarity = if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) { self.bump(); // `!` @@ -618,7 +626,7 @@ impl<'a> Parser<'a> { err_path(ty_first.span) } }; - let trait_ref = TraitRef { path, ref_id: ty_first.id }; + let trait_ref = TraitRef { path, constness, ref_id: ty_first.id }; ItemKind::Impl( unsafety, From 0cf52a7dd8fbe68e85471fd9254d8e2e025a03d8 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Jan 2020 15:50:18 -0800 Subject: [PATCH 40/48] Parse `?const Trait` bound syntax The grammar also handles `?const ?Trait` even though this is semantically redundant. --- src/librustc_parse/parser/ty.rs | 91 ++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index f96c82a1ab37d..ea14aa278ac29 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -6,7 +6,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_error_codes::*; use rustc_errors::{pluralize, struct_span_err, Applicability, PResult}; use rustc_span::source_map::Span; -use rustc_span::symbol::kw; +use rustc_span::symbol::{kw, sym}; use syntax::ast::{ self, BareFnTy, FunctionRetTy, GenericParam, Ident, Lifetime, MutTy, Ty, TyKind, }; @@ -17,6 +17,24 @@ use syntax::ast::{Mac, Mutability}; use syntax::ptr::P; use syntax::token::{self, Token}; +/// Any `?` or `?const` modifiers that appear at the start of a bound. +struct BoundModifiers { + /// `?Trait`. + maybe: Option, + + /// `?const Trait`. + maybe_const: Option, +} + +impl BoundModifiers { + fn trait_bound_modifier(&self) -> TraitBoundModifier { + match self.maybe { + Some(_) => TraitBoundModifier::Maybe, + None => TraitBoundModifier::None, + } + } +} + /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, /// `IDENT<::AssocTy>`. /// @@ -195,7 +213,9 @@ impl<'a> Parser<'a> { lo: Span, parse_plus: bool, ) -> PResult<'a, TyKind> { - let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); + assert_ne!(self.token, token::Question); + + let poly_trait_ref = PolyTraitRef::new(generic_params, path, None, lo.to(self.prev_span)); let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; if parse_plus { self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded @@ -421,12 +441,15 @@ impl<'a> Parser<'a> { let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; let is_negative = self.eat(&token::Not); - let question = self.eat(&token::Question).then_some(self.prev_span); + + let modifiers = self.parse_ty_bound_modifiers(); let bound = if self.token.is_lifetime() { - self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)? + self.error_lt_bound_with_modifiers(modifiers); + self.parse_generic_lt_bound(lo, inner_lo, has_parens)? } else { - self.parse_generic_ty_bound(lo, has_parens, question)? + self.parse_generic_ty_bound(lo, has_parens, modifiers)? }; + Ok(if is_negative { Err(anchor_lo.to(self.prev_span)) } else { Ok(bound) }) } @@ -439,9 +462,7 @@ impl<'a> Parser<'a> { lo: Span, inner_lo: Span, has_parens: bool, - question: Option, ) -> PResult<'a, GenericBound> { - self.error_opt_out_lifetime(question); let bound = GenericBound::Outlives(self.expect_lifetime()); if has_parens { // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, @@ -451,8 +472,17 @@ impl<'a> Parser<'a> { Ok(bound) } - fn error_opt_out_lifetime(&self, question: Option) { - if let Some(span) = question { + /// Emits an error if any trait bound modifiers were present. + fn error_lt_bound_with_modifiers(&self, modifiers: BoundModifiers) { + if let Some(span) = modifiers.maybe_const { + self.struct_span_err( + span, + "`?const` may only modify trait bounds, not lifetime bounds", + ) + .emit(); + } + + if let Some(span) = modifiers.maybe { self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds") .emit(); } @@ -478,25 +508,58 @@ impl<'a> Parser<'a> { Ok(()) } + /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `?const Trait`. + /// + /// If no modifiers are present, this does not consume any tokens. + /// + /// ``` + /// TY_BOUND_MODIFIERS = "?" ["const" ["?"]] + /// ``` + fn parse_ty_bound_modifiers(&mut self) -> BoundModifiers { + if !self.eat(&token::Question) { + return BoundModifiers { maybe: None, maybe_const: None }; + } + + // `? ...` + let first_question = self.prev_span; + if !self.eat_keyword(kw::Const) { + return BoundModifiers { maybe: Some(first_question), maybe_const: None }; + } + + // `?const ...` + let maybe_const = first_question.to(self.prev_span); + self.sess.gated_spans.gate(sym::const_trait_bound_opt_out, maybe_const); + if !self.eat(&token::Question) { + return BoundModifiers { maybe: None, maybe_const: Some(maybe_const) }; + } + + // `?const ? ...` + let second_question = self.prev_span; + BoundModifiers { maybe: Some(second_question), maybe_const: Some(maybe_const) } + } + /// Parses a type bound according to: /// ``` /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) - /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) + /// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS] [for] SIMPLE_PATH /// ``` + /// + /// For example, this grammar accepts `?const ?for<'a: 'b> m::Trait<'a>`. fn parse_generic_ty_bound( &mut self, lo: Span, has_parens: bool, - question: Option, + modifiers: BoundModifiers, ) -> PResult<'a, GenericBound> { let lifetime_defs = self.parse_late_bound_lifetime_defs()?; let path = self.parse_path(PathStyle::Type)?; if has_parens { self.expect(&token::CloseDelim(token::Paren))?; } - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); - let modifier = question.map_or(TraitBoundModifier::None, |_| TraitBoundModifier::Maybe); - Ok(GenericBound::Trait(poly_trait, modifier)) + + let constness = modifiers.maybe_const.map(|_| ast::Constness::NotConst); + let poly_trait = PolyTraitRef::new(lifetime_defs, path, constness, lo.to(self.prev_span)); + Ok(GenericBound::Trait(poly_trait, modifiers.trait_bound_modifier())) } /// Optionally parses `for<$generic_params>`. From b390fc4cf1e7293716cd8d80ec532df232022324 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Jan 2020 16:35:07 -0800 Subject: [PATCH 41/48] Error when new syntax is lowered This means the new syntax will always fail to compile, even when the feature gate is enabled. These checks will be removed in a later PR once the implementation is done. --- src/librustc_ast_lowering/item.rs | 6 ++++++ src/librustc_ast_lowering/lib.rs | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index a5892a22d9dfa..7c95b2a86c685 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -71,6 +71,12 @@ impl<'a, 'lowering, 'hir> Visitor<'a> for ItemLowerer<'a, 'lowering, 'hir> { self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { let this = &mut ItemLowerer { lctx: this }; if let ItemKind::Impl(.., ref opt_trait_ref, _, _) = item.kind { + if opt_trait_ref.as_ref().map(|tr| tr.constness.is_some()).unwrap_or(false) { + this.lctx + .diagnostic() + .span_err(item.span, "const trait impls are not yet implemented"); + } + this.with_trait_impl_ref(opt_trait_ref, |this| visit::walk_item(this, item)); } else { visit::walk_item(this, item); diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 385153b62ce82..73d1e49725826 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -2579,6 +2579,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &PolyTraitRef, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::PolyTraitRef<'hir> { + if p.trait_ref.constness.is_some() { + self.diagnostic().span_err(p.span, "`?const` on trait bounds is not yet implemented"); + } + let bound_generic_params = self.lower_generic_params( &p.bound_generic_params, &NodeMap::default(), From 31edbe9acacceb24f0e31a73e0c45f852977c663 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 3 Jan 2020 16:32:01 -0800 Subject: [PATCH 42/48] Reject `const` in inherent impls --- src/librustc_parse/parser/item.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 86ab8bf57a3e3..b209e5a78266a 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -5,7 +5,7 @@ use crate::maybe_whole; use rustc_error_codes::*; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey}; -use rustc_span::source_map::{self, respan, Span}; +use rustc_span::source_map::{self, respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::BytePos; use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; @@ -560,8 +560,9 @@ impl<'a> Parser<'a> { }; let constness = if self.eat_keyword(kw::Const) { - self.sess.gated_spans.gate(sym::const_trait_impl, self.prev_span); - Some(Constness::Const) + let span = self.prev_span; + self.sess.gated_spans.gate(sym::const_trait_impl, span); + Some(respan(span, Constness::Const)) } else { None }; @@ -626,6 +627,7 @@ impl<'a> Parser<'a> { err_path(ty_first.span) } }; + let constness = constness.map(|c| c.node); let trait_ref = TraitRef { path, constness, ref_id: ty_first.id }; ItemKind::Impl( @@ -639,6 +641,13 @@ impl<'a> Parser<'a> { ) } None => { + // Reject `impl const Type {}` here + if let Some(Spanned { node: Constness::Const, span }) = constness { + self.struct_span_err(span, "`const` cannot modify an inherent impl") + .help("only a trait impl can be `const`") + .emit(); + } + // impl Type ItemKind::Impl( unsafety, From d843e002bb836be3164bef80d6218228aec974a8 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 4 Jan 2020 16:29:45 -0800 Subject: [PATCH 43/48] Check for `?const` in invalid contexts during AST validation --- src/librustc_passes/ast_validation.rs | 74 +++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 5000cd5f52f65..1e5e39217b7aa 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -24,6 +24,23 @@ use syntax::walk_list; use rustc_error_codes::*; +#[derive(Clone, Copy)] +enum BoundContext { + ImplTrait, + TraitBounds, + TraitObject, +} + +impl BoundContext { + fn description(&self) -> &'static str { + match self { + Self::ImplTrait => "`impl Trait`", + Self::TraitBounds => "supertraits", + Self::TraitObject => "trait objects", + } + } +} + struct AstValidator<'a> { session: &'a Session, has_proc_macro_decls: bool, @@ -33,6 +50,11 @@ struct AstValidator<'a> { /// e.g., `impl Iterator`. outer_impl_trait: Option, + /// Tracks the context in which a bound can appear. + /// + /// This is used to forbid `?const Trait` bounds in certain contexts. + bound_context_stack: Vec>, + /// Used to ban `impl Trait` in path projections like `::Item` /// or `Foo::Bar` is_impl_trait_banned: bool, @@ -58,9 +80,21 @@ impl<'a> AstValidator<'a> { } fn with_impl_trait(&mut self, outer: Option, f: impl FnOnce(&mut Self)) { + self.bound_context_stack.push(outer.map(|_| BoundContext::ImplTrait)); let old = mem::replace(&mut self.outer_impl_trait, outer); f(self); self.outer_impl_trait = old; + self.bound_context_stack.pop(); + } + + fn with_bound_context(&mut self, ctx: Option, f: impl FnOnce(&mut Self)) { + self.bound_context_stack.push(ctx); + f(self); + self.bound_context_stack.pop(); + } + + fn innermost_bound_context(&mut self) -> Option { + self.bound_context_stack.iter().rev().find(|x| x.is_some()).copied().flatten() } fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) { @@ -84,6 +118,11 @@ impl<'a> AstValidator<'a> { TyKind::ImplTrait(..) => { self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) } + TyKind::TraitObject(..) => { + self.with_bound_context(Some(BoundContext::TraitObject), |this| { + visit::walk_ty(this, t) + }); + } TyKind::Path(ref qself, ref path) => { // We allow these: // - `Option` @@ -192,6 +231,8 @@ impl<'a> AstValidator<'a> { } } + // FIXME(ecstaticmorse): Instead, use the `bound_context_stack` to check this in + // `visit_param_bound`. fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) { for bound in bounds { if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound { @@ -697,6 +738,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } self.no_questions_in_bounds(bounds, "supertraits", true); + + // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound + // context for the supertraits. + self.visit_generics(generics); + self.with_bound_context(Some(BoundContext::TraitBounds), |this| { + walk_list!(this, visit_param_bound, bounds); + }); + walk_list!(self, visit_trait_item, trait_items); + return; } ItemKind::Mod(_) => { // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). @@ -841,6 +891,29 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_generic_param(self, param); } + fn visit_param_bound(&mut self, bound: &'a GenericBound) { + if let GenericBound::Trait(poly, maybe_bound) = bound { + match poly.trait_ref.constness { + Some(Constness::NotConst) => { + if *maybe_bound == TraitBoundModifier::Maybe { + self.err_handler() + .span_err(bound.span(), "`?const` and `?` are mutually exclusive"); + } + + if let Some(ctx) = self.innermost_bound_context() { + let msg = format!("`?const` is not permitted in {}", ctx.description()); + self.err_handler().span_err(bound.span(), &msg); + } + } + + Some(Constness::Const) => bug!("Parser should reject bare `const` on bounds"), + None => {} + } + } + + visit::walk_param_bound(self, bound) + } + fn visit_pat(&mut self, pat: &'a Pat) { match pat.kind { PatKind::Lit(ref expr) => { @@ -949,6 +1022,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffe session, has_proc_macro_decls: false, outer_impl_trait: None, + bound_context_stack: Vec::new(), is_impl_trait_banned: false, is_assoc_ty_bound_banned: false, lint_buffer: lints, From 343e1570a9b460e3dda85fe87fd6819df99d7943 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 2 Jan 2020 16:31:30 -0800 Subject: [PATCH 44/48] Add tests for RFC 2632 --- src/test/ui/parser/bounds-type.rs | 5 ++ src/test/ui/parser/bounds-type.stderr | 8 ++- .../feature-gate.gated.stderr | 8 +++ .../const-trait-bound-opt-out/feature-gate.rs | 15 ++++++ .../feature-gate.stock.stderr | 18 +++++++ .../in-impl-trait.rs | 25 ++++++++++ .../in-impl-trait.stderr | 50 +++++++++++++++++++ .../in-trait-bounds.rs | 9 ++++ .../in-trait-bounds.stderr | 14 ++++++ .../in-trait-object.rs | 18 +++++++ .../in-trait-object.stderr | 26 ++++++++++ .../opt-out-twice.rs | 8 +++ .../opt-out-twice.stderr | 14 ++++++ .../const-trait-bound-opt-out/syntax.rs | 10 ++++ .../without-question-mark.rs | 7 +++ .../without-question-mark.stderr | 8 +++ .../feature-gate.gated.stderr | 8 +++ .../rfc-2632-const-trait-impl/feature-gate.rs | 13 +++++ .../feature-gate.stock.stderr | 18 +++++++ .../impl-opt-out-trait.rs | 11 ++++ .../impl-opt-out-trait.stderr | 8 +++ .../inherent-impl.rs | 14 ++++++ .../inherent-impl.stderr | 10 ++++ .../ui/rfc-2632-const-trait-impl/syntax.rs | 9 ++++ 24 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/syntax.rs diff --git a/src/test/ui/parser/bounds-type.rs b/src/test/ui/parser/bounds-type.rs index 9122cb49ebc1a..7a187a0518af9 100644 --- a/src/test/ui/parser/bounds-type.rs +++ b/src/test/ui/parser/bounds-type.rs @@ -8,6 +8,11 @@ struct S< T: ?for<'a> Trait, // OK T: Tr +, // OK T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds + + T: ?const Tr, // OK + T: ?const ?Tr, // OK + T: ?const Tr + 'a, // OK + T: ?const 'a, //~ ERROR `?const` may only modify trait bounds, not lifetime bounds >; fn main() {} diff --git a/src/test/ui/parser/bounds-type.stderr b/src/test/ui/parser/bounds-type.stderr index 0b714e40a1012..9a1f2ed398240 100644 --- a/src/test/ui/parser/bounds-type.stderr +++ b/src/test/ui/parser/bounds-type.stderr @@ -4,5 +4,11 @@ error: `?` may only modify trait bounds, not lifetime bounds LL | T: ?'a, | ^ -error: aborting due to previous error +error: `?const` may only modify trait bounds, not lifetime bounds + --> $DIR/bounds-type.rs:15:8 + | +LL | T: ?const 'a, + | ^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr new file mode 100644 index 0000000000000..0bf337ad08dbf --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr @@ -0,0 +1,8 @@ +error: `?const` on trait bounds is not yet implemented + --> $DIR/feature-gate.rs:11:29 + | +LL | const fn get_assoc_const() -> i32 { ::CONST } + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs new file mode 100644 index 0000000000000..cf1ed30da0fcc --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs @@ -0,0 +1,15 @@ +// revisions: stock gated +// gate-test-const_trait_bound_opt_out + +#![cfg_attr(gated, feature(const_trait_bound_opt_out))] +#![allow(incomplete_features)] + +trait T { + const CONST: i32; +} + +const fn get_assoc_const() -> i32 { ::CONST } +//[stock]~^ ERROR `?const` on trait bounds is experimental +//[stock,gated]~^^ ERROR `?const` on trait bounds is not yet implemented + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr new file mode 100644 index 0000000000000..64388004b5b72 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr @@ -0,0 +1,18 @@ +error[E0658]: `?const` on trait bounds is experimental + --> $DIR/feature-gate.rs:11:29 + | +LL | const fn get_assoc_const() -> i32 { ::CONST } + | ^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/67794 + = help: add `#![feature(const_trait_bound_opt_out)]` to the crate attributes to enable + +error: `?const` on trait bounds is not yet implemented + --> $DIR/feature-gate.rs:11:29 + | +LL | const fn get_assoc_const() -> i32 { ::CONST } + | ^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs new file mode 100644 index 0000000000000..e4e6bedd93746 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs @@ -0,0 +1,25 @@ +#![feature(const_trait_bound_opt_out)] +#![feature(associated_type_bounds)] +#![allow(incomplete_features)] + +trait T {} +struct S; +impl T for S {} + +fn rpit() -> impl ?const T { S } +//~^ ERROR `?const` is not permitted in `impl Trait` +//~| ERROR `?const` on trait bounds is not yet implemented + +fn apit(_: impl ?const T) {} +//~^ ERROR `?const` is not permitted in `impl Trait` +//~| ERROR `?const` on trait bounds is not yet implemented + +fn rpit_assoc_bound() -> impl IntoIterator { Some(S) } +//~^ ERROR `?const` is not permitted in `impl Trait` +//~| ERROR `?const` on trait bounds is not yet implemented + +fn apit_assoc_bound(_: impl IntoIterator) {} +//~^ ERROR `?const` is not permitted in `impl Trait` +//~| ERROR `?const` on trait bounds is not yet implemented + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr new file mode 100644 index 0000000000000..f4abd4b714e8a --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr @@ -0,0 +1,50 @@ +error: `?const` is not permitted in `impl Trait` + --> $DIR/in-impl-trait.rs:9:19 + | +LL | fn rpit() -> impl ?const T { S } + | ^^^^^^^^ + +error: `?const` is not permitted in `impl Trait` + --> $DIR/in-impl-trait.rs:13:17 + | +LL | fn apit(_: impl ?const T) {} + | ^^^^^^^^ + +error: `?const` is not permitted in `impl Trait` + --> $DIR/in-impl-trait.rs:17:50 + | +LL | fn rpit_assoc_bound() -> impl IntoIterator { Some(S) } + | ^^^^^^^^ + +error: `?const` is not permitted in `impl Trait` + --> $DIR/in-impl-trait.rs:21:48 + | +LL | fn apit_assoc_bound(_: impl IntoIterator) {} + | ^^^^^^^^ + +error: `?const` on trait bounds is not yet implemented + --> $DIR/in-impl-trait.rs:9:19 + | +LL | fn rpit() -> impl ?const T { S } + | ^^^^^^^^ + +error: `?const` on trait bounds is not yet implemented + --> $DIR/in-impl-trait.rs:13:17 + | +LL | fn apit(_: impl ?const T) {} + | ^^^^^^^^ + +error: `?const` on trait bounds is not yet implemented + --> $DIR/in-impl-trait.rs:17:50 + | +LL | fn rpit_assoc_bound() -> impl IntoIterator { Some(S) } + | ^^^^^^^^ + +error: `?const` on trait bounds is not yet implemented + --> $DIR/in-impl-trait.rs:21:48 + | +LL | fn apit_assoc_bound(_: impl IntoIterator) {} + | ^^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs new file mode 100644 index 0000000000000..4523b46bc51f6 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs @@ -0,0 +1,9 @@ +#![feature(const_trait_bound_opt_out)] +#![allow(incomplete_features)] + +trait Super {} +trait T: ?const Super {} +//~^ ERROR `?const` is not permitted in supertraits +//~| ERROR `?const` on trait bounds is not yet implemented + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr new file mode 100644 index 0000000000000..8003361be7d2e --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr @@ -0,0 +1,14 @@ +error: `?const` is not permitted in supertraits + --> $DIR/in-trait-bounds.rs:5:10 + | +LL | trait T: ?const Super {} + | ^^^^^^^^^^^^ + +error: `?const` on trait bounds is not yet implemented + --> $DIR/in-trait-bounds.rs:5:10 + | +LL | trait T: ?const Super {} + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs new file mode 100644 index 0000000000000..490fae6d91a15 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs @@ -0,0 +1,18 @@ +#![feature(const_trait_bound_opt_out)] +#![allow(bare_trait_objects)] +#![allow(incomplete_features)] + +struct S; +trait T {} +impl T for S {} + +// An inherent impl for the trait object `?const T`. +impl ?const T {} +//~^ ERROR `?const` is not permitted in trait objects +//~| ERROR `?const` on trait bounds is not yet implemented + +fn trait_object() -> &'static dyn ?const T { &S } +//~^ ERROR `?const` is not permitted in trait objects +//~| ERROR `?const` on trait bounds is not yet implemented + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr new file mode 100644 index 0000000000000..19d52e51b3797 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr @@ -0,0 +1,26 @@ +error: `?const` is not permitted in trait objects + --> $DIR/in-trait-object.rs:10:6 + | +LL | impl ?const T {} + | ^^^^^^^^ + +error: `?const` is not permitted in trait objects + --> $DIR/in-trait-object.rs:14:35 + | +LL | fn trait_object() -> &'static dyn ?const T { &S } + | ^^^^^^^^ + +error: `?const` on trait bounds is not yet implemented + --> $DIR/in-trait-object.rs:10:6 + | +LL | impl ?const T {} + | ^^^^^^^^ + +error: `?const` on trait bounds is not yet implemented + --> $DIR/in-trait-object.rs:14:35 + | +LL | fn trait_object() -> &'static dyn ?const T { &S } + | ^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.rs new file mode 100644 index 0000000000000..01e941a8fba45 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.rs @@ -0,0 +1,8 @@ +// compile-flags: -Z parse-only + +#![feature(const_trait_bound_opt_out)] +#![allow(incomplete_features)] + +struct S; +//~^ ERROR expected identifier, found keyword `const` +//~| ERROR expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>` diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.stderr new file mode 100644 index 0000000000000..f7924b3f24db3 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.stderr @@ -0,0 +1,14 @@ +error: expected identifier, found keyword `const` + --> $DIR/opt-out-twice.rs:6:21 + | +LL | struct S; + | ^^^^^ expected identifier, found keyword + +error: expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>`, found `Tr` + --> $DIR/opt-out-twice.rs:6:27 + | +LL | struct S; + | ^^ expected one of 7 possible tokens + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs new file mode 100644 index 0000000000000..a0d9610bbb5e2 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs @@ -0,0 +1,10 @@ +// compile-flags: -Z parse-only +// check-pass + +#![feature(const_trait_bound_opt_out)] +#![allow(incomplete_features)] + +struct S< + T: ?const ?for<'a> Tr<'a> + 'static + ?const std::ops::Add, + T: ?const ?for<'a: 'b> m::Trait<'a>, +>; diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.rs new file mode 100644 index 0000000000000..b904a2eec0dd0 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.rs @@ -0,0 +1,7 @@ +// compile-flags: -Z parse-only + +#![feature(const_trait_bound_opt_out)] +#![allow(incomplete_features)] + +struct S; +//~^ ERROR expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, lifetime, or path diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.stderr new file mode 100644 index 0000000000000..0dbca952c037e --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, lifetime, or path, found keyword `const` + --> $DIR/without-question-mark.rs:6:13 + | +LL | struct S; + | ^^^^^ expected one of 9 possible tokens + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr new file mode 100644 index 0000000000000..b196f9ef57380 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr @@ -0,0 +1,8 @@ +error: const trait impls are not yet implemented + --> $DIR/feature-gate.rs:9:1 + | +LL | impl const T for S {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs new file mode 100644 index 0000000000000..49b6c0926c50c --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs @@ -0,0 +1,13 @@ +// revisions: stock gated +// gate-test-const_trait_impl + +#![cfg_attr(gated, feature(const_trait_impl))] +#![allow(incomplete_features)] + +struct S; +trait T {} +impl const T for S {} +//[stock]~^ ERROR const trait impls are experimental +//[stock,gated]~^^ ERROR const trait impls are not yet implemented + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr new file mode 100644 index 0000000000000..093946f859ac3 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr @@ -0,0 +1,18 @@ +error[E0658]: const trait impls are experimental + --> $DIR/feature-gate.rs:9:6 + | +LL | impl const T for S {} + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/67792 + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: const trait impls are not yet implemented + --> $DIR/feature-gate.rs:9:1 + | +LL | impl const T for S {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs new file mode 100644 index 0000000000000..98d3a220d8674 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs @@ -0,0 +1,11 @@ +#![feature(const_trait_bound_opt_out)] +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +struct S; +trait T {} + +impl ?const T for S {} +//~^ ERROR expected a trait, found type + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.stderr new file mode 100644 index 0000000000000..8f923efb093f3 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.stderr @@ -0,0 +1,8 @@ +error: expected a trait, found type + --> $DIR/impl-opt-out-trait.rs:8:6 + | +LL | impl ?const T for S {} + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs new file mode 100644 index 0000000000000..9cffe75addd63 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs @@ -0,0 +1,14 @@ +// compile-flags: -Z parse-only + +#![feature(const_trait_impl)] +#![feature(const_trait_bound_opt_out)] +#![allow(incomplete_features)] +#![allow(bare_trait_objects)] + +struct S; +trait T {} + +impl const T {} +//~^ ERROR `const` cannot modify an inherent impl + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr new file mode 100644 index 0000000000000..1d24557655951 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr @@ -0,0 +1,10 @@ +error: `const` cannot modify an inherent impl + --> $DIR/inherent-impl.rs:11:6 + | +LL | impl const T {} + | ^^^^^ + | + = help: only a trait impl can be `const` + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2632-const-trait-impl/syntax.rs b/src/test/ui/rfc-2632-const-trait-impl/syntax.rs new file mode 100644 index 0000000000000..354d48d630f7b --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/syntax.rs @@ -0,0 +1,9 @@ +// compile-flags: -Z parse-only +// check-pass + +#![feature(const_trait_bound_opt_out)] +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +// For now, this parses since an error does not occur until AST lowering. +impl ?const T {} From b6b11f0f282081b2baa3961cc9f78313eafcc8b4 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 4 Jan 2020 18:34:10 -0800 Subject: [PATCH 45/48] Call all visit methods on trait definitions --- src/librustc_passes/ast_validation.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 1e5e39217b7aa..cb035e586c109 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -741,11 +741,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound // context for the supertraits. + self.visit_vis(&item.vis); + self.visit_ident(item.ident); self.visit_generics(generics); self.with_bound_context(Some(BoundContext::TraitBounds), |this| { walk_list!(this, visit_param_bound, bounds); }); walk_list!(self, visit_trait_item, trait_items); + walk_list!(self, visit_attribute, &item.attrs); return; } ItemKind::Mod(_) => { From 9950a1f3bdfec11db6bbe2019b819b4410e26905 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 4 Jan 2020 21:47:11 -0800 Subject: [PATCH 46/48] Add test for `?const` and `?` on the same bound --- .../const-trait-bound-opt-out/with-maybe-sized.rs | 8 ++++++++ .../with-maybe-sized.stderr | 14 ++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs new file mode 100644 index 0000000000000..425784f4e4326 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs @@ -0,0 +1,8 @@ +#![feature(const_trait_bound_opt_out)] +#![allow(incomplete_features)] + +struct S(std::marker::PhantomData); +//~^ ERROR `?const` and `?` are mutually exclusive +//~| ERROR `?const` on trait bounds is not yet implemented + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr new file mode 100644 index 0000000000000..44f6d464ae6a8 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr @@ -0,0 +1,14 @@ +error: `?const` and `?` are mutually exclusive + --> $DIR/with-maybe-sized.rs:4:13 + | +LL | struct S(std::marker::PhantomData); + | ^^^^^^^^^^^^^ + +error: `?const` on trait bounds is not yet implemented + --> $DIR/with-maybe-sized.rs:4:13 + | +LL | struct S(std::marker::PhantomData); + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 14730ed44536b5d50aa8b73fbb1023fffe6eba3d Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 5 Jan 2020 16:33:26 -0800 Subject: [PATCH 47/48] Make `bound_context` more like neighboring functions --- src/librustc_passes/ast_validation.rs | 39 +++++++++++++-------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index cb035e586c109..724d717304c20 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -24,6 +24,7 @@ use syntax::walk_list; use rustc_error_codes::*; +/// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`). #[derive(Clone, Copy)] enum BoundContext { ImplTrait, @@ -50,10 +51,11 @@ struct AstValidator<'a> { /// e.g., `impl Iterator`. outer_impl_trait: Option, - /// Tracks the context in which a bound can appear. + /// Keeps track of the `BoundContext` as we recurse. /// - /// This is used to forbid `?const Trait` bounds in certain contexts. - bound_context_stack: Vec>, + /// This is used to forbid `?const Trait` bounds in, e.g., + /// `impl Iterator`. + bound_context: Option, /// Used to ban `impl Trait` in path projections like `::Item` /// or `Foo::Bar` @@ -80,21 +82,19 @@ impl<'a> AstValidator<'a> { } fn with_impl_trait(&mut self, outer: Option, f: impl FnOnce(&mut Self)) { - self.bound_context_stack.push(outer.map(|_| BoundContext::ImplTrait)); let old = mem::replace(&mut self.outer_impl_trait, outer); - f(self); + if outer.is_some() { + self.with_bound_context(BoundContext::ImplTrait, |this| f(this)); + } else { + f(self) + } self.outer_impl_trait = old; - self.bound_context_stack.pop(); } - fn with_bound_context(&mut self, ctx: Option, f: impl FnOnce(&mut Self)) { - self.bound_context_stack.push(ctx); + fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) { + let old = self.bound_context.replace(ctx); f(self); - self.bound_context_stack.pop(); - } - - fn innermost_bound_context(&mut self) -> Option { - self.bound_context_stack.iter().rev().find(|x| x.is_some()).copied().flatten() + self.bound_context = old; } fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) { @@ -119,9 +119,7 @@ impl<'a> AstValidator<'a> { self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) } TyKind::TraitObject(..) => { - self.with_bound_context(Some(BoundContext::TraitObject), |this| { - visit::walk_ty(this, t) - }); + self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t)); } TyKind::Path(ref qself, ref path) => { // We allow these: @@ -231,8 +229,7 @@ impl<'a> AstValidator<'a> { } } - // FIXME(ecstaticmorse): Instead, use the `bound_context_stack` to check this in - // `visit_param_bound`. + // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`. fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) { for bound in bounds { if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound { @@ -744,7 +741,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visit_vis(&item.vis); self.visit_ident(item.ident); self.visit_generics(generics); - self.with_bound_context(Some(BoundContext::TraitBounds), |this| { + self.with_bound_context(BoundContext::TraitBounds, |this| { walk_list!(this, visit_param_bound, bounds); }); walk_list!(self, visit_trait_item, trait_items); @@ -903,7 +900,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .span_err(bound.span(), "`?const` and `?` are mutually exclusive"); } - if let Some(ctx) = self.innermost_bound_context() { + if let Some(ctx) = self.bound_context { let msg = format!("`?const` is not permitted in {}", ctx.description()); self.err_handler().span_err(bound.span(), &msg); } @@ -1025,7 +1022,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffe session, has_proc_macro_decls: false, outer_impl_trait: None, - bound_context_stack: Vec::new(), + bound_context: None, is_impl_trait_banned: false, is_assoc_ty_bound_banned: false, lint_buffer: lints, From fd1c00348b7b3521f7340a2d034b32406229fe1b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 5 Jan 2020 16:34:26 -0800 Subject: [PATCH 48/48] Add test for `?const` in nested impl/dyn trait --- .../const-trait-bound-opt-out/in-trait-object.rs | 4 ++++ .../in-trait-object.stderr | 14 +++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs index 490fae6d91a15..6cfca71548674 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs @@ -15,4 +15,8 @@ fn trait_object() -> &'static dyn ?const T { &S } //~^ ERROR `?const` is not permitted in trait objects //~| ERROR `?const` on trait bounds is not yet implemented +fn trait_object_in_apit(_: impl IntoIterator>) {} +//~^ ERROR `?const` is not permitted in trait objects +//~| ERROR `?const` on trait bounds is not yet implemented + fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr index 19d52e51b3797..c059f16902250 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr @@ -10,6 +10,12 @@ error: `?const` is not permitted in trait objects LL | fn trait_object() -> &'static dyn ?const T { &S } | ^^^^^^^^ +error: `?const` is not permitted in trait objects + --> $DIR/in-trait-object.rs:18:61 + | +LL | fn trait_object_in_apit(_: impl IntoIterator>) {} + | ^^^^^^^^ + error: `?const` on trait bounds is not yet implemented --> $DIR/in-trait-object.rs:10:6 | @@ -22,5 +28,11 @@ error: `?const` on trait bounds is not yet implemented LL | fn trait_object() -> &'static dyn ?const T { &S } | ^^^^^^^^ -error: aborting due to 4 previous errors +error: `?const` on trait bounds is not yet implemented + --> $DIR/in-trait-object.rs:18:61 + | +LL | fn trait_object_in_apit(_: impl IntoIterator>) {} + | ^^^^^^^^ + +error: aborting due to 6 previous errors