From 11adc1300cbff4970f97f9f647ab51bb0db872df Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 23 Jun 2018 00:21:35 +0100 Subject: [PATCH 01/41] Address minor comments --- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/subst.rs | 1 - src/librustc_lint/types.rs | 8 -------- src/librustc_passes/ast_validation.rs | 5 +---- src/librustc_privacy/lib.rs | 13 +++++-------- src/librustc_resolve/lib.rs | 9 +++++---- 6 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6c27d527ae891..4479c7239df50 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -931,7 +931,7 @@ impl<'a, 'gcx, 'tcx> Generics { pub fn requires_monomorphization(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { for param in &self.params { match param.kind { - GenericParamDefKind::Type {..} => return true, + GenericParamDefKind::Type { .. } => return true, GenericParamDefKind::Lifetime => {} } } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 2e3c6df9754df..a6ff979f472af 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -231,7 +231,6 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { mk_kind: &mut F) where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx> { - if let Some(def_id) = defs.parent { let parent_defs = tcx.generics_of(def_id); Substs::fill_item(substs, tcx, parent_defs, mk_kind); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f1636c4dcb08a..2a30aeb6a39d6 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -819,14 +819,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { if let hir::ItemKind::Enum(ref enum_definition, _) = it.node { let item_def_id = cx.tcx.hir.local_def_id(it.id); - let generics = cx.tcx.generics_of(item_def_id); - for param in &generics.params { - match param.kind { - ty::GenericParamDefKind::Lifetime { .. } => {}, - ty::GenericParamDefKind::Type { .. } => return, - } - } - // Sizes only make sense for non-generic types. let t = cx.tcx.type_of(item_def_id); let ty = cx.tcx.erase_regions(&t); match cx.layout_of(ty) { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 0ea90e7453190..110797a59cb7c 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -539,10 +539,7 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) { match *generic_args { GenericArgs::AngleBracketed(ref data) => { - data.args.iter().for_each(|arg| match arg { - GenericArg::Type(ty) => self.visit_ty(ty), - _ => {} - }); + data.args.iter().for_each(|arg| self.visit_generic_arg(arg)); for type_binding in &data.bindings { // Type bindings such as `Item=impl Debug` in `Iterator` // are allowed to contain nested `impl Trait`. diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index fcb1b65014be0..d9c3fc221dce1 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -23,7 +23,7 @@ extern crate rustc_typeck; extern crate syntax_pos; extern crate rustc_data_structures; -use rustc::hir::{self, GenericParamKind, PatKind}; +use rustc::hir::{self, PatKind}; use rustc::hir::def::Def; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -1270,14 +1270,11 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_generics(&mut self, generics: &'tcx hir::Generics) { - generics.params.iter().for_each(|param| match param.kind { - GenericParamKind::Lifetime { .. } => {} - GenericParamKind::Type { .. } => { - for bound in ¶m.bounds { - self.check_generic_bound(bound); - } + for param in &generics.params { + for bound in ¶m.bounds { + self.check_generic_bound(bound); } - }); + } for predicate in &generics.where_clause.predicates { match predicate { &hir::WherePredicate::BoundPredicate(ref bound_pred) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2e163cb4c6a37..83d068a3df807 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -822,11 +822,12 @@ impl<'a, 'tcx, 'cl> Visitor<'tcx> for Resolver<'a, 'cl> { .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => None, GenericParamKind::Type { ref default, .. } => { - if found_default || default.is_some() { - found_default = true; - return Some((Ident::with_empty_ctxt(param.ident.name), Def::Err)); + found_default |= default.is_some(); + if found_default { + Some((Ident::with_empty_ctxt(param.ident.name), Def::Err)); + } else { + None } - None } })); From 651215e2837e5f667f412fb28d3c849fbfbd3852 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 23 Jun 2018 00:33:03 +0100 Subject: [PATCH 02/41] Replace for_each with for --- src/librustc_metadata/encoder.rs | 18 +++++----- src/librustc_resolve/lib.rs | 42 +++++++++++----------- src/librustc_save_analysis/dump_visitor.rs | 42 ++++++++++++---------- 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 02a41e68f68cb..3acf30a94fb24 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1683,15 +1683,17 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { } fn encode_info_for_generics(&mut self, generics: &hir::Generics) { - generics.params.iter().for_each(|param| match param.kind { - hir::GenericParamKind::Lifetime { .. } => {} - hir::GenericParamKind::Type { ref default, .. } => { - let def_id = self.tcx.hir.local_def_id(param.id); - let has_default = Untracked(default.is_some()); - let encode_info = IsolatedEncoder::encode_info_for_ty_param; - self.record(def_id, encode_info, (def_id, has_default)); + for param in &generics.params { + match param.kind { + hir::GenericParamKind::Lifetime { .. } => {} + hir::GenericParamKind::Type { ref default, .. } => { + let def_id = self.tcx.hir.local_def_id(param.id); + let has_default = Untracked(default.is_some()); + let encode_info = IsolatedEncoder::encode_info_for_ty_param; + self.record(def_id, encode_info, (def_id, has_default)); + } } - }); + } } fn encode_info_for_ty(&mut self, ty: &hir::Ty) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 83d068a3df807..45c5dd2e5eb35 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2340,28 +2340,30 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { HasTypeParameters(generics, rib_kind) => { let mut function_type_rib = Rib::new(rib_kind); let mut seen_bindings = FxHashMap(); - generics.params.iter().for_each(|param| match param.kind { - GenericParamKind::Lifetime { .. } => {} - GenericParamKind::Type { .. } => { - let ident = param.ident.modern(); - debug!("with_type_parameter_rib: {}", param.id); - - if seen_bindings.contains_key(&ident) { - let span = seen_bindings.get(&ident).unwrap(); - let err = ResolutionError::NameAlreadyUsedInTypeParameterList( - ident.name, - span, - ); - resolve_error(self, param.ident.span, err); - } - seen_bindings.entry(ident).or_insert(param.ident.span); + for param in &generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => {} + GenericParamKind::Type { .. } => { + let ident = param.ident.modern(); + debug!("with_type_parameter_rib: {}", param.id); + + if seen_bindings.contains_key(&ident) { + let span = seen_bindings.get(&ident).unwrap(); + let err = ResolutionError::NameAlreadyUsedInTypeParameterList( + ident.name, + span, + ); + resolve_error(self, param.ident.span, err); + } + seen_bindings.entry(ident).or_insert(param.ident.span); - // Plain insert (no renaming). - let def = Def::TyParam(self.definitions.local_def_id(param.id)); - function_type_rib.bindings.insert(ident, def); - self.record_def(param.id, PathResolution::new(def)); + // Plain insert (no renaming). + let def = Def::TyParam(self.definitions.local_def_id(param.id)); + function_type_rib.bindings.insert(ident, def); + self.record_def(param.id, PathResolution::new(def)); + } } - }); + } self.ribs[TypeNS].push(function_type_rib); } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 04a4bca4ffbda..090a39720d837 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -824,10 +824,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { if let Some(ref generic_args) = seg.args { match **generic_args { ast::GenericArgs::AngleBracketed(ref data) => { - data.args.iter().for_each(|arg| match arg { - ast::GenericArg::Type(ty) => self.visit_ty(ty), - _ => {} - }); + for arg in &data.args { + match arg { + ast::GenericArg::Type(ty) => self.visit_ty(ty), + _ => {} + } + } } ast::GenericArgs::Parenthesized(ref data) => { for t in &data.inputs { @@ -911,10 +913,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { // Explicit types in the turbo-fish. if let Some(ref generic_args) = seg.args { if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args { - data.args.iter().for_each(|arg| match arg { - ast::GenericArg::Type(ty) => self.visit_ty(ty), - _ => {} - }); + for arg in &data.args { + match arg { + ast::GenericArg::Type(ty) => self.visit_ty(ty), + _ => {} + } + } } } @@ -1522,19 +1526,21 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc } fn visit_generics(&mut self, generics: &'l ast::Generics) { - generics.params.iter().for_each(|param| match param.kind { - ast::GenericParamKind::Lifetime { .. } => {} - ast::GenericParamKind::Type { ref default, .. } => { - for bound in ¶m.bounds { - if let ast::GenericBound::Trait(ref trait_ref, _) = *bound { - self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path) + for param in &generics.params { + match param.kind { + ast::GenericParamKind::Lifetime { .. } => {} + ast::GenericParamKind::Type { ref default, .. } => { + for bound in ¶m.bounds { + if let ast::GenericBound::Trait(ref trait_ref, _) = *bound { + self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path) + } + } + if let Some(ref ty) = default { + self.visit_ty(&ty); } - } - if let Some(ref ty) = default { - self.visit_ty(&ty); } } - }); + } } fn visit_ty(&mut self, t: &'l ast::Ty) { From 2317abdd019cce8137c857160fc4cd78431f565c Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 23 Jun 2018 00:44:17 +0100 Subject: [PATCH 03/41] Fix quadratic loop in confirm.rs --- src/librustc_resolve/lib.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 47 ++++++++++----------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 45c5dd2e5eb35..22047d6b6eee2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -824,7 +824,7 @@ impl<'a, 'tcx, 'cl> Visitor<'tcx> for Resolver<'a, 'cl> { GenericParamKind::Type { ref default, .. } => { found_default |= default.is_some(); if found_default { - Some((Ident::with_empty_ctxt(param.ident.name), Def::Err)); + Some((Ident::with_empty_ctxt(param.ident.name), Def::Err)) } else { None } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 6c3e265619fea..ca0467606d438 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -324,37 +324,34 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { assert_eq!(method_generics.parent_count, parent_substs.len()); let provided = &segment.args; let own_counts = method_generics.own_counts(); + // FIXME(varkor): Separating out the parameters is messy. + let lifetimes: Vec<_> = provided.iter().flat_map(|data| data.args.iter().filter_map(|arg| match arg { + GenericArg::Lifetime(ty) => Some(ty), + _ => None, + })).collect(); + let types: Vec<_> = provided.iter().flat_map(|data| data.args.iter().filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty), + _ => None, + })).collect(); Substs::for_item(self.tcx, pick.item.def_id, |param, _| { - let mut i = param.index as usize; + let i = param.index as usize; if i < parent_substs.len() { parent_substs[i] } else { - let (is_lt, is_ty) = match param.kind { - GenericParamDefKind::Lifetime => (true, false), - GenericParamDefKind::Type { .. } => (false, true), - }; - provided.as_ref().and_then(|data| { - for arg in &data.args { - match arg { - GenericArg::Lifetime(lt) if is_lt => { - if i == parent_substs.len() { - return Some(AstConv::ast_region_to_region( - self.fcx, lt, Some(param)).into()); - } - i -= 1; - } - GenericArg::Lifetime(_) => {} - GenericArg::Type(ty) if is_ty => { - if i == parent_substs.len() + own_counts.lifetimes { - return Some(self.to_ty(ty).into()); - } - i -= 1; - } - GenericArg::Type(_) => {} + match param.kind { + GenericParamDefKind::Lifetime => { + if let Some(lifetime) = lifetimes.get(i - parent_substs.len()) { + return AstConv::ast_region_to_region( + self.fcx, lifetime, Some(param)).into(); } } - None - }).unwrap_or_else(|| self.var_for_def(self.span, param)) + GenericParamDefKind::Type { .. } => { + if let Some(ast_ty) = types.get(i - parent_substs.len() - own_counts.lifetimes) { + return self.to_ty(ast_ty).into(); + } + } + } + self.var_for_def(self.span, param) } }) } From d1a82af23575dad3d7af2760dac6db0132b9a2d1 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 25 Jun 2018 19:52:50 +0100 Subject: [PATCH 04/41] Refactor mod/check (part i) --- src/librustc_typeck/check/method/confirm.rs | 4 +- src/librustc_typeck/check/mod.rs | 264 ++++++++++++-------- 2 files changed, 166 insertions(+), 102 deletions(-) diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index ca0467606d438..a48552f9dcff8 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -315,9 +315,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let method_generics = self.tcx.generics_of(pick.item.def_id); - let mut fn_segment = Some((segment, method_generics)); + let fn_segment = Some((segment, method_generics)); let supress_mismatch = self.fcx.check_impl_trait(self.span, fn_segment); - self.fcx.check_generic_arg_count(self.span, &mut fn_segment, true, supress_mismatch); + self.fcx.check_generic_arg_count(self.span, &segment, &method_generics, true, supress_mismatch); // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 27b427f7f89fb..d8617149def7a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -113,7 +113,7 @@ use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, NodeMap}; use std::cell::{Cell, RefCell, Ref, RefMut}; use rustc_data_structures::sync::Lrc; -use std::collections::hash_map::Entry; +use std::collections::{hash_map::Entry, HashSet}; use std::cmp; use std::fmt::Display; use std::iter; @@ -505,6 +505,9 @@ impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> { } } +#[derive(Debug)] +struct PathSeg(DefId, usize); + pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { body_id: ast::NodeId, @@ -4770,20 +4773,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.span_suggestion(span_semi, "consider removing this semicolon", "".to_string()); } - // Instantiates the given path, which must refer to an item with the given - // number of type parameters and type. - pub fn instantiate_value_path(&self, - segments: &[hir::PathSegment], - opt_self_ty: Option>, - def: Def, - span: Span, - node_id: ast::NodeId) - -> Ty<'tcx> { - debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})", - segments, - def, - node_id); - + fn def_ids_for_path_segments(&self, + segments: &[hir::PathSegment], + def: Def) + -> Vec { // We need to extract the type parameters supplied by the user in // the path `path`. Due to the current setup, this is a bit of a // tricky-process; the problem is that resolve only tells us the @@ -4829,10 +4822,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The first step then is to categorize the segments appropriately. assert!(!segments.is_empty()); + let last = segments.len() - 1; + + let mut path_segs = vec![]; - let mut ufcs_associated = None; - let mut type_segment = None; - let mut fn_segment = None; match def { // Case 1. Reference to a struct/variant constructor. Def::StructCtor(def_id, ..) | @@ -4840,22 +4833,58 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Everything but the final segment should have no // parameters at all. let mut generics = self.tcx.generics_of(def_id); - if let Some(def_id) = generics.parent { - // Variant and struct constructors use the - // generics of their parent type definition. - generics = self.tcx.generics_of(def_id); - } - type_segment = Some((segments.last().unwrap(), generics)); + // Variant and struct constructors use the + // generics of their parent type definition. + let generics_def_id = generics.parent.unwrap_or(def_id); + path_segs.push(PathSeg(generics_def_id, last)); } // Case 2. Reference to a top-level value. Def::Fn(def_id) | Def::Const(def_id) | Def::Static(def_id, _) => { - fn_segment = Some((segments.last().unwrap(), self.tcx.generics_of(def_id))); + path_segs.push(PathSeg(def_id, last)); } // Case 3. Reference to a method or associated const. + Def::Method(def_id) | + Def::AssociatedConst(def_id) => { + if segments.len() >= 2 { + let generics = self.tcx.generics_of(def_id); + path_segs.push(PathSeg(generics.parent.unwrap(), last - 1)); + } + path_segs.push(PathSeg(def_id, last)); + } + + // Case 4. Local variable, no generics. + Def::Local(..) | Def::Upvar(..) => {} + + _ => bug!("unexpected definition: {:?}", def), + } + + debug!("path_segs = {:?}", path_segs); + + path_segs + } + + // Instantiates the given path, which must refer to an item with the given + // number of type parameters and type. + pub fn instantiate_value_path(&self, + segments: &[hir::PathSegment], + opt_self_ty: Option>, + def: Def, + span: Span, + node_id: ast::NodeId) + -> Ty<'tcx> { + debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})", + segments, + def, + node_id); + + let path_segs = self.def_ids_for_path_segments(segments, def); + + let mut ufcs_associated = None; + match def { Def::Method(def_id) | Def::AssociatedConst(def_id) => { let container = self.tcx.associated_item(def_id).container; @@ -4865,34 +4894,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } ty::ImplContainer(_) => {} } - - let generics = self.tcx.generics_of(def_id); - if segments.len() >= 2 { - let parent_generics = self.tcx.generics_of(generics.parent.unwrap()); - type_segment = Some((&segments[segments.len() - 2], parent_generics)); - } else { + if segments.len() == 1 { // `::assoc` will end up here, and so can `T::assoc`. let self_ty = opt_self_ty.expect("UFCS sugared assoc missing Self"); ufcs_associated = Some((container, self_ty)); } - fn_segment = Some((segments.last().unwrap(), generics)); } - - // Case 4. Local variable, no generics. - Def::Local(..) | Def::Upvar(..) => {} - - _ => bug!("unexpected definition: {:?}", def), + _ => {} } - debug!("type_segment={:?} fn_segment={:?}", type_segment, fn_segment); - // Now that we have categorized what space the parameters for each // segment belong to, let's sort out the parameters that the user // provided (if any) into their appropriate spaces. We'll also report // errors if type parameters are provided in an inappropriate place. - let poly_segments = type_segment.is_some() as usize + - fn_segment.is_some() as usize; - AstConv::prohibit_generics(self, &segments[..segments.len() - poly_segments]); + let mut generic_segs = HashSet::new(); + for PathSeg(_, index) in &path_segs { + generic_segs.insert(index); + } + let segs: Vec<_> = segments + .iter() + .enumerate() + .filter_map(|(index, seg)| { + if !generic_segs.contains(&index) { + Some(seg) + } else { + None + } + }) + .cloned() + .collect(); + AstConv::prohibit_generics(self, &segs); match def { Def::Local(nid) | Def::Upvar(nid, ..) => { @@ -4904,6 +4935,46 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } + let mut type_segment = None; + let mut fn_segment = None; + match def { + // Case 1. Reference to a struct/variant constructor. + Def::StructCtor(def_id, ..) | + Def::VariantCtor(def_id, ..) => { + // Everything but the final segment should have no + // parameters at all. + let mut generics = self.tcx.generics_of(def_id); + if let Some(def_id) = generics.parent { + // Variant and struct constructors use the + // generics of their parent type definition. + generics = self.tcx.generics_of(def_id); + } + type_segment = Some((segments.last().unwrap(), generics)); + } + + // Case 2. Reference to a top-level value. + Def::Fn(def_id) | + Def::Const(def_id) | + Def::Static(def_id, _) => { + fn_segment = Some((segments.last().unwrap(), self.tcx.generics_of(def_id))); + } + + // Case 3. Reference to a method or associated const. + Def::Method(def_id) | + Def::AssociatedConst(def_id) => { + let generics = self.tcx.generics_of(def_id); + if segments.len() >= 2 { + let parent_generics = self.tcx.generics_of(generics.parent.unwrap()); + type_segment = Some((&segments[segments.len() - 2], parent_generics)); + } + fn_segment = Some((segments.last().unwrap(), generics)); + } + + _ => {} + } + + debug!("type_segment={:?} fn_segment={:?}", type_segment, fn_segment); + // Now we have to compare the types that the user *actually* // provided against the types that were *expected*. If the user // did not provide any types, then we want to substitute inference @@ -4911,17 +4982,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // to add defaults. If the user provided *too many* types, that's // a problem. let supress_mismatch = self.check_impl_trait(span, fn_segment); - self.check_generic_arg_count(span, &mut type_segment, false, supress_mismatch); - self.check_generic_arg_count(span, &mut fn_segment, false, supress_mismatch); + for &PathSeg(def_id, index) in &path_segs { + let generics = self.tcx.generics_of(def_id); + self.check_generic_arg_count(span, &segments[index], &generics, false, supress_mismatch); + } - let (fn_start, has_self) = match (type_segment, fn_segment) { - (_, Some((_, generics))) => { - (generics.parent_count, generics.has_self) - } - (Some((_, generics)), None) => { - (generics.params.len(), generics.has_self) - } - (None, None) => (0, false) + let has_self = path_segs.last().map(|PathSeg(def_id, _)| { + self.tcx.generics_of(*def_id).has_self + }).unwrap_or(false); + + let fn_start = match (type_segment, fn_segment) { + (_, Some((_, generics))) => generics.parent_count, + (Some((_, generics)), None) => generics.params.len(), + (None, None) => 0, }; // FIXME(varkor): Separating out the parameters is messy. let mut lifetimes_type_seg = vec![]; @@ -5091,64 +5164,55 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Report errors if the provided parameters are too few or too many. fn check_generic_arg_count(&self, span: Span, - segment: &mut Option<(&hir::PathSegment, &ty::Generics)>, + segment: &hir::PathSegment, + generics: &ty::Generics, is_method_call: bool, supress_mismatch_error: bool) { - let (lifetimes, types, infer_types, bindings) = segment.map_or( - (vec![], vec![], true, &[][..]), - |(s, _)| { - s.args.as_ref().map_or( - (vec![], vec![], s.infer_types, &[][..]), - |data| { - let (mut lifetimes, mut types) = (vec![], vec![]); - data.args.iter().for_each(|arg| match arg { - GenericArg::Lifetime(lt) => lifetimes.push(lt), - GenericArg::Type(ty) => types.push(ty), - }); - (lifetimes, types, s.infer_types, &data.bindings[..]) - } - ) + let (mut lifetimes, mut types) = (vec![], vec![]); + let infer_types = segment.infer_types; + let mut bindings = vec![]; + if let Some(ref data) = segment.args { + data.args.iter().for_each(|arg| match arg { + GenericArg::Lifetime(lt) => lifetimes.push(lt.clone()), + GenericArg::Type(ty) => types.push(ty.clone()), }); + bindings = data.bindings.clone().to_vec(); + } - // Check provided parameters. - let ((ty_required, ty_accepted), lt_accepted) = - segment.map_or(((0, 0), 0), |(_, generics)| { - struct ParamRange { - required: usize, - accepted: usize - }; + struct ParamRange { + required: usize, + accepted: usize + }; - let mut lt_accepted = 0; - let mut ty_params = ParamRange { required: 0, accepted: 0 }; - for param in &generics.params { - match param.kind { - GenericParamDefKind::Lifetime => lt_accepted += 1, - GenericParamDefKind::Type { has_default, .. } => { - ty_params.accepted += 1; - if !has_default { - ty_params.required += 1; - } - } - }; - } - if generics.parent.is_none() && generics.has_self { - ty_params.required -= 1; - ty_params.accepted -= 1; + let mut lt_accepted = 0; + let mut ty_params = ParamRange { required: 0, accepted: 0 }; + for param in &generics.params { + match param.kind { + GenericParamDefKind::Lifetime => lt_accepted += 1, + GenericParamDefKind::Type { has_default, .. } => { + ty_params.accepted += 1; + if !has_default { + ty_params.required += 1; + } } + }; + } + if generics.parent.is_none() && generics.has_self { + ty_params.required -= 1; + ty_params.accepted -= 1; + } + let ty_accepted = ty_params.accepted; + let ty_required = ty_params.required; - ((ty_params.required, ty_params.accepted), lt_accepted) - }); - - let count_type_params = |n| { - format!("{} type parameter{}", n, if n == 1 { "" } else { "s" }) - }; + let count_type_params = |n| format!("{} type parameter{}", n, if n == 1 { "" } else { "s" }); let expected_text = count_type_params(ty_accepted); let actual_text = count_type_params(types.len()); if let Some((mut err, span)) = if types.len() > ty_accepted { // To prevent derived errors to accumulate due to extra // type parameters, we force instantiate_value_path to // use inference variables instead of the provided types. - *segment = None; + // FIXME(varkor) + // *segment = None; let span = types[ty_accepted].span; Some((struct_span_err!(self.tcx.sess, span, E0087, "too many type parameters provided: \ @@ -5172,8 +5236,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let infer_lifetimes = lifetimes.len() == 0; // Prohibit explicit lifetime arguments if late bound lifetime parameters are present. - let has_late_bound_lifetime_defs = - segment.map_or(None, |(_, generics)| generics.has_late_bound_regions); + let has_late_bound_lifetime_defs = generics.has_late_bound_regions; if let (Some(span_late), false) = (has_late_bound_lifetime_defs, lifetimes.is_empty()) { // Report this as a lint only if no error was reported previously. let primary_msg = "cannot specify lifetime arguments explicitly \ @@ -5184,7 +5247,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut err = self.tcx.sess.struct_span_err(lifetimes[0].span, primary_msg); err.span_note(span_late, note_msg); err.emit(); - *segment = None; + // FIXME(varkor) + // *segment = None; } else { let mut multispan = MultiSpan::from_span(lifetimes[0].span); multispan.push_span_label(span_late, note_msg.to_string()); From 5fe9aeb40234a92fc02f07dfa76c3dbe570efd45 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 26 Jun 2018 19:48:50 +0100 Subject: [PATCH 05/41] Refactor mod/check (part ii) --- src/librustc/ty/subst.rs | 8 +- src/librustc_typeck/check/mod.rs | 158 ++++++++++++++++++++----------- 2 files changed, 106 insertions(+), 60 deletions(-) diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index a6ff979f472af..0bee400f449fe 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -226,9 +226,9 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } fn fill_item(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - defs: &ty::Generics, - mk_kind: &mut F) + tcx: TyCtxt<'a, 'gcx, 'tcx>, + defs: &ty::Generics, + mk_kind: &mut F) where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx> { if let Some(def_id) = defs.parent { @@ -238,7 +238,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { Substs::fill_single(substs, defs, mk_kind) } - fn fill_single(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, + pub fn fill_single(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, defs: &ty::Generics, mk_kind: &mut F) where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx> diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d8617149def7a..4b16cbbf75048 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -103,6 +103,8 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::query::Providers; use rustc::ty::util::{Representability, IntTypeExt, Discr}; use errors::{DiagnosticBuilder, DiagnosticId}; +use rustc_data_structures::accumulate_vec::AccumulateVec; +use rustc_data_structures::array_vec::ArrayVec; use require_c_abi_if_variadic; use session::{CompileIncomplete, config, Session}; @@ -5002,10 +5004,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut infer_types_type_seg = true; if let Some((seg, _)) = type_segment { if let Some(ref data) = seg.args { - for arg in &data.args { + for (i, arg) in data.args.iter().enumerate() { match arg { - GenericArg::Lifetime(lt) => lifetimes_type_seg.push(lt), - GenericArg::Type(ty) => types_type_seg.push(ty), + GenericArg::Lifetime(lt) => lifetimes_type_seg.push((i, lt)), + GenericArg::Type(ty) => types_type_seg.push((i, ty)), } } } @@ -5017,74 +5019,118 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut infer_types_fn_seg = true; if let Some((seg, _)) = fn_segment { if let Some(ref data) = seg.args { - for arg in &data.args { + for (i, arg) in data.args.iter().enumerate() { match arg { - GenericArg::Lifetime(lt) => lifetimes_fn_seg.push(lt), - GenericArg::Type(ty) => types_fn_seg.push(ty), + GenericArg::Lifetime(lt) => lifetimes_fn_seg.push((i, lt)), + GenericArg::Type(ty) => types_fn_seg.push((i, ty)), } } } infer_types_fn_seg = seg.infer_types; } - let substs = Substs::for_item(self.tcx, def.def_id(), |param, substs| { - let mut i = param.index as usize; - - let (segment, lifetimes, types, infer_types) = if i < fn_start { - if let GenericParamDefKind::Type { .. } = param.kind { - // Handle Self first, so we can adjust the index to match the AST. - if has_self && i == 0 { - return opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| { - self.var_for_def(span, param) - }); + let defs = self.tcx.generics_of(def.def_id()); + let count = defs.count(); + let mut substs = if count <= 8 { + AccumulateVec::Array(ArrayVec::new()) + } else { + AccumulateVec::Heap(Vec::with_capacity(count)) + }; + let mut stack = vec![def.def_id()]; + let mut parent_defs = defs; + while let Some(def_id) = parent_defs.parent { + parent_defs = self.tcx.generics_of(def_id); + stack.push(def_id); + } + while let Some(def_id) = stack.pop() { + let defs = self.tcx.generics_of(def_id); + Substs::fill_single(&mut substs, defs, &mut |param: &ty::GenericParamDef, substs| { + let mut i = param.index as usize; + + let (lifetimes, types, infer_types) = if i < fn_start { + if let GenericParamDefKind::Type { .. } = param.kind { + // Handle Self first, so we can adjust the index to match the AST. + if has_self && i == 0 { + return opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| { + self.var_for_def(span, param) + }); + } } - } - i -= has_self as usize; - (type_segment, &lifetimes_type_seg, &types_type_seg, infer_types_type_seg) - } else { - i -= fn_start; - (fn_segment, &lifetimes_fn_seg, &types_fn_seg, infer_types_fn_seg) - }; + i -= has_self as usize; + (&lifetimes_type_seg, &types_type_seg, infer_types_type_seg) + } else { + i -= fn_start; + (&lifetimes_fn_seg, &types_fn_seg, infer_types_fn_seg) + }; - match param.kind { - GenericParamDefKind::Lifetime => { - if let Some(lifetime) = lifetimes.get(i) { - AstConv::ast_region_to_region(self, lifetime, Some(param)).into() - } else { - self.re_infer(span, Some(param)).unwrap().into() + let mut pi = param.index as usize - has_self as usize; + + let segment = if let Some(&PathSeg(_, ind)) = path_segs.iter().find(|&PathSeg(di, _)| *di == def_id) { + let seg = &segments[ind]; + if lifetimes.len() == 0 { + pi -= defs.own_counts().lifetimes; } - } - GenericParamDefKind::Type { .. } => { - // Skip over the lifetimes in the same segment. - if let Some((_, generics)) = segment { - i -= generics.own_counts().lifetimes; + + Some((seg, defs)) + } else { + None + }; + + // eprintln!("{:?} {:?} {:?}", param.index, i, segment); + + + + match param.kind { + GenericParamDefKind::Lifetime => { + if let Some((z, lt)) = lifetimes.get(i) { + eprintln!("lifetime {:?} {:?} {:?}", pi, z, has_self); + if pi != *z { + eprintln!("error {:?} {:?} {:?} {:?} {:?} {:?}", pi, z, i, segment, fn_start, has_self); + bug!("uh oh") + } + AstConv::ast_region_to_region(self, lt, Some(param)).into() + } else { + self.re_infer(span, Some(param)).unwrap().into() + } } + GenericParamDefKind::Type { .. } => { + // Skip over the lifetimes in the same segment. + if let Some((_, generics)) = segment { + i -= generics.own_counts().lifetimes; + } - let has_default = match param.kind { - GenericParamDefKind::Type { has_default, .. } => has_default, - _ => unreachable!() - }; + let has_default = match param.kind { + GenericParamDefKind::Type { has_default, .. } => has_default, + _ => unreachable!() + }; - if let Some(ast_ty) = types.get(i) { - // A provided type parameter. - self.to_ty(ast_ty).into() - } else if !infer_types && has_default { - // No type parameter provided, but a default exists. - let default = self.tcx.type_of(param.def_id); - self.normalize_ty( - span, - default.subst_spanned(self.tcx, substs, Some(span)) - ).into() - } else { - // No type parameters were provided, we can infer all. - // This can also be reached in some error cases: - // We prefer to use inference variables instead of - // TyError to let type inference recover somewhat. - self.var_for_def(span, param) + if let Some((z, ty)) = types.get(i) { + eprintln!("type {:?} {:?} {:?}", pi, z, has_self); + if pi != *z { + eprintln!("error {:?} {:?} {:?} {:?} {:?} {:?}", pi, z, i, segment, fn_start, has_self); + bug!("uh oh") + } + // A provided type parameter. + self.to_ty(ty).into() + } else if !infer_types && has_default { + // No type parameter provided, but a default exists. + let default = self.tcx.type_of(param.def_id); + self.normalize_ty( + span, + default.subst_spanned(self.tcx, substs, Some(span)) + ).into() + } else { + // No type parameters were provided, we can infer all. + // This can also be reached in some error cases: + // We prefer to use inference variables instead of + // TyError to let type inference recover somewhat. + self.var_for_def(span, param) + } } } - } - }); + }); + } + let substs = self.tcx.intern_substs(&substs); // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. From 96379e1659eb18daeaf7f86e9c8b69332a22b534 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 26 Jun 2018 20:24:13 +0100 Subject: [PATCH 06/41] Refactor mod/check (part iii) --- src/librustc_typeck/check/mod.rs | 85 ++++++++++++++------------------ 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4b16cbbf75048..98ec101c27499 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5001,7 +5001,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // FIXME(varkor): Separating out the parameters is messy. let mut lifetimes_type_seg = vec![]; let mut types_type_seg = vec![]; - let mut infer_types_type_seg = true; + let mut _infer_types_type_seg = true; if let Some((seg, _)) = type_segment { if let Some(ref data) = seg.args { for (i, arg) in data.args.iter().enumerate() { @@ -5011,12 +5011,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - infer_types_type_seg = seg.infer_types; + _infer_types_type_seg = seg.infer_types; } let mut lifetimes_fn_seg = vec![]; let mut types_fn_seg = vec![]; - let mut infer_types_fn_seg = true; + let mut _infer_types_fn_seg = true; if let Some((seg, _)) = fn_segment { if let Some(ref data) = seg.args { for (i, arg) in data.args.iter().enumerate() { @@ -5026,7 +5026,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - infer_types_fn_seg = seg.infer_types; + _infer_types_fn_seg = seg.infer_types; } let defs = self.tcx.generics_of(def.def_id()); @@ -5045,74 +5045,61 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { while let Some(def_id) = stack.pop() { let defs = self.tcx.generics_of(def_id); Substs::fill_single(&mut substs, defs, &mut |param: &ty::GenericParamDef, substs| { - let mut i = param.index as usize; - - let (lifetimes, types, infer_types) = if i < fn_start { + let lifetimes = if (param.index as usize) < fn_start { if let GenericParamDefKind::Type { .. } = param.kind { // Handle Self first, so we can adjust the index to match the AST. - if has_self && i == 0 { + if has_self && param.index == 0 { return opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| { self.var_for_def(span, param) }); } } - i -= has_self as usize; - (&lifetimes_type_seg, &types_type_seg, infer_types_type_seg) + &lifetimes_type_seg } else { - i -= fn_start; - (&lifetimes_fn_seg, &types_fn_seg, infer_types_fn_seg) + &lifetimes_fn_seg }; let mut pi = param.index as usize - has_self as usize; - let segment = if let Some(&PathSeg(_, ind)) = path_segs.iter().find(|&PathSeg(di, _)| *di == def_id) { + let (_segment, infer_types) = if let Some(&PathSeg(_, ind)) = path_segs.iter().find(|&PathSeg(di, _)| *di == def_id) { let seg = &segments[ind]; if lifetimes.len() == 0 { pi -= defs.own_counts().lifetimes; } - Some((seg, defs)) + if let Some(ref data) = seg.args { + if let Some(arg) = data.args.get(pi) { + return match param.kind { + GenericParamDefKind::Lifetime => { + let lt = match arg { + GenericArg::Lifetime(lt) => lt, + _ => bug!("should be a lifetime"), + }; + AstConv::ast_region_to_region(self, lt, Some(param)).into() + } + GenericParamDefKind::Type { .. } => { + // A provided type parameter. + let ty = match arg { + GenericArg::Type(ty) => ty, + _ => bug!("should be a type"), + }; + self.to_ty(ty).into() + } + }; + } + } + + (Some((seg, defs)), seg.infer_types) } else { - None + (None, true) }; - // eprintln!("{:?} {:?} {:?}", param.index, i, segment); - - - match param.kind { GenericParamDefKind::Lifetime => { - if let Some((z, lt)) = lifetimes.get(i) { - eprintln!("lifetime {:?} {:?} {:?}", pi, z, has_self); - if pi != *z { - eprintln!("error {:?} {:?} {:?} {:?} {:?} {:?}", pi, z, i, segment, fn_start, has_self); - bug!("uh oh") - } - AstConv::ast_region_to_region(self, lt, Some(param)).into() - } else { - self.re_infer(span, Some(param)).unwrap().into() - } + self.re_infer(span, Some(param)).unwrap().into() } - GenericParamDefKind::Type { .. } => { - // Skip over the lifetimes in the same segment. - if let Some((_, generics)) = segment { - i -= generics.own_counts().lifetimes; - } - - let has_default = match param.kind { - GenericParamDefKind::Type { has_default, .. } => has_default, - _ => unreachable!() - }; - - if let Some((z, ty)) = types.get(i) { - eprintln!("type {:?} {:?} {:?}", pi, z, has_self); - if pi != *z { - eprintln!("error {:?} {:?} {:?} {:?} {:?} {:?}", pi, z, i, segment, fn_start, has_self); - bug!("uh oh") - } - // A provided type parameter. - self.to_ty(ty).into() - } else if !infer_types && has_default { + GenericParamDefKind::Type { has_default, .. } => { + if !infer_types && has_default { // No type parameter provided, but a default exists. let default = self.tcx.type_of(param.def_id); self.normalize_ty( From e812b55d8f627146d352cfb640c1b21c0975ca28 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 26 Jun 2018 23:08:02 +0100 Subject: [PATCH 07/41] Refactor mod/check (part iv) --- src/librustc_typeck/check/mod.rs | 119 +++++++++++-------------------- 1 file changed, 43 insertions(+), 76 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 98ec101c27499..68881d928d516 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4983,115 +4983,82 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // variables. If the user provided some types, we may still need // to add defaults. If the user provided *too many* types, that's // a problem. + let mut infer_lifetimes = FxHashMap(); let supress_mismatch = self.check_impl_trait(span, fn_segment); for &PathSeg(def_id, index) in &path_segs { let generics = self.tcx.generics_of(def_id); - self.check_generic_arg_count(span, &segments[index], &generics, false, supress_mismatch); + let seg = &segments[index]; + self.check_generic_arg_count(span, seg, &generics, false, supress_mismatch); + infer_lifetimes.insert(index, if let Some(ref data) = seg.args { + !data.args.iter().any(|arg| match arg { + GenericArg::Lifetime(_) => true, + _ => false, + }) + } else { + true + }); } let has_self = path_segs.last().map(|PathSeg(def_id, _)| { self.tcx.generics_of(*def_id).has_self }).unwrap_or(false); - let fn_start = match (type_segment, fn_segment) { - (_, Some((_, generics))) => generics.parent_count, - (Some((_, generics)), None) => generics.params.len(), - (None, None) => 0, - }; - // FIXME(varkor): Separating out the parameters is messy. - let mut lifetimes_type_seg = vec![]; - let mut types_type_seg = vec![]; - let mut _infer_types_type_seg = true; - if let Some((seg, _)) = type_segment { - if let Some(ref data) = seg.args { - for (i, arg) in data.args.iter().enumerate() { - match arg { - GenericArg::Lifetime(lt) => lifetimes_type_seg.push((i, lt)), - GenericArg::Type(ty) => types_type_seg.push((i, ty)), - } - } - } - _infer_types_type_seg = seg.infer_types; - } - - let mut lifetimes_fn_seg = vec![]; - let mut types_fn_seg = vec![]; - let mut _infer_types_fn_seg = true; - if let Some((seg, _)) = fn_segment { - if let Some(ref data) = seg.args { - for (i, arg) in data.args.iter().enumerate() { - match arg { - GenericArg::Lifetime(lt) => lifetimes_fn_seg.push((i, lt)), - GenericArg::Type(ty) => types_fn_seg.push((i, ty)), - } - } - } - _infer_types_fn_seg = seg.infer_types; - } - - let defs = self.tcx.generics_of(def.def_id()); + let def_id = def.def_id(); + let defs = self.tcx.generics_of(def_id); let count = defs.count(); let mut substs = if count <= 8 { AccumulateVec::Array(ArrayVec::new()) } else { AccumulateVec::Heap(Vec::with_capacity(count)) }; - let mut stack = vec![def.def_id()]; let mut parent_defs = defs; + let mut stack = vec![(def_id, parent_defs)]; while let Some(def_id) = parent_defs.parent { parent_defs = self.tcx.generics_of(def_id); - stack.push(def_id); + stack.push((def_id, parent_defs)); } - while let Some(def_id) = stack.pop() { - let defs = self.tcx.generics_of(def_id); + while let Some((def_id, defs)) = stack.pop() { Substs::fill_single(&mut substs, defs, &mut |param: &ty::GenericParamDef, substs| { - let lifetimes = if (param.index as usize) < fn_start { + if param.index == 0 && has_self { if let GenericParamDefKind::Type { .. } = param.kind { // Handle Self first, so we can adjust the index to match the AST. - if has_self && param.index == 0 { - return opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| { - self.var_for_def(span, param) - }); - } + return opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| { + self.var_for_def(span, param) + }); } - &lifetimes_type_seg - } else { - &lifetimes_fn_seg - }; - - let mut pi = param.index as usize - has_self as usize; + } - let (_segment, infer_types) = if let Some(&PathSeg(_, ind)) = path_segs.iter().find(|&PathSeg(di, _)| *di == def_id) { - let seg = &segments[ind]; - if lifetimes.len() == 0 { - pi -= defs.own_counts().lifetimes; - } + let infer_types = if let Some(&PathSeg(_, index)) = path_segs + .iter() + .find(|&PathSeg(di, _)| *di == def_id) { - if let Some(ref data) = seg.args { - if let Some(arg) = data.args.get(pi) { + if let Some(ref data) = segments[index].args { + let lifetime_offset = if infer_lifetimes[&index] { + defs.own_counts().lifetimes + } else { + 0 + }; + let param_idx = param.index as usize - has_self as usize - lifetime_offset; + if let Some(arg) = data.args.get(param_idx) { return match param.kind { - GenericParamDefKind::Lifetime => { - let lt = match arg { - GenericArg::Lifetime(lt) => lt, - _ => bug!("should be a lifetime"), - }; - AstConv::ast_region_to_region(self, lt, Some(param)).into() + GenericParamDefKind::Lifetime => match arg { + GenericArg::Lifetime(lt) => { + AstConv::ast_region_to_region(self, lt, Some(param)).into() + } + _ => bug!("expected a lifetime arg"), } - GenericParamDefKind::Type { .. } => { + GenericParamDefKind::Type { .. } => match arg { // A provided type parameter. - let ty = match arg { - GenericArg::Type(ty) => ty, - _ => bug!("should be a type"), - }; - self.to_ty(ty).into() + GenericArg::Type(ty) => self.to_ty(ty).into(), + _ => bug!("expected a type arg"), } - }; + } } } - (Some((seg, defs)), seg.infer_types) + segments[index].infer_types } else { - (None, true) + true }; match param.kind { From c9941a8a859e89cfebd4e85f8f9581c6b91e4f14 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 26 Jun 2018 23:34:33 +0100 Subject: [PATCH 08/41] Refactor mod/check (part v) --- src/librustc_typeck/check/method/confirm.rs | 3 +- src/librustc_typeck/check/mod.rs | 47 ++++++++++----------- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index a48552f9dcff8..d7d81b605c08d 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -315,8 +315,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let method_generics = self.tcx.generics_of(pick.item.def_id); - let fn_segment = Some((segment, method_generics)); - let supress_mismatch = self.fcx.check_impl_trait(self.span, fn_segment); + let supress_mismatch = self.fcx.check_impl_trait(self.span, segment, &method_generics); self.fcx.check_generic_arg_count(self.span, &segment, &method_generics, true, supress_mismatch); // Create subst for early-bound lifetime parameters, combining diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 68881d928d516..331e6df8539cd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4984,10 +4984,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // to add defaults. If the user provided *too many* types, that's // a problem. let mut infer_lifetimes = FxHashMap(); - let supress_mismatch = self.check_impl_trait(span, fn_segment); for &PathSeg(def_id, index) in &path_segs { - let generics = self.tcx.generics_of(def_id); let seg = &segments[index]; + let generics = self.tcx.generics_of(def_id); + let supress_mismatch = self.check_impl_trait(span, seg, &generics); self.check_generic_arg_count(span, seg, &generics, false, supress_mismatch); infer_lifetimes.insert(index, if let Some(ref data) = seg.args { !data.args.iter().any(|arg| match arg { @@ -5284,33 +5284,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Report error if there is an explicit type parameter when using `impl Trait`. fn check_impl_trait(&self, span: Span, - segment: Option<(&hir::PathSegment, &ty::Generics)>) + seg: &hir::PathSegment, + generics: &ty::Generics) -> bool { - let segment = segment.map(|(path_segment, generics)| { - let explicit = !path_segment.infer_types; - let impl_trait = generics.params.iter().any(|param| match param.kind { - ty::GenericParamDefKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. - } => true, - _ => false, - }); - - if explicit && impl_trait { - let mut err = struct_span_err! { - self.tcx.sess, - span, - E0632, - "cannot provide explicit type parameters when `impl Trait` is \ - used in argument position." - }; + let explicit = !seg.infer_types; + let impl_trait = generics.params.iter().any(|param| match param.kind { + ty::GenericParamDefKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. + } => true, + _ => false, + }); - err.emit(); - } + if explicit && impl_trait { + let mut err = struct_span_err! { + self.tcx.sess, + span, + E0632, + "cannot provide explicit type parameters when `impl Trait` is \ + used in argument position." + }; - impl_trait - }); + err.emit(); + } - segment.unwrap_or(false) + impl_trait } // Resolves `typ` by a single level if `typ` is a type variable. From 88d5b2f4b4e4f0a44606f17f2eb5120507b7ed1e Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 28 Jun 2018 22:04:51 +0100 Subject: [PATCH 09/41] Refactor mod/check (part vi) --- src/librustc_typeck/check/mod.rs | 56 ++++---------------------------- 1 file changed, 7 insertions(+), 49 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 331e6df8539cd..bbf41ddb81ba0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4937,46 +4937,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } - let mut type_segment = None; - let mut fn_segment = None; - match def { - // Case 1. Reference to a struct/variant constructor. - Def::StructCtor(def_id, ..) | - Def::VariantCtor(def_id, ..) => { - // Everything but the final segment should have no - // parameters at all. - let mut generics = self.tcx.generics_of(def_id); - if let Some(def_id) = generics.parent { - // Variant and struct constructors use the - // generics of their parent type definition. - generics = self.tcx.generics_of(def_id); - } - type_segment = Some((segments.last().unwrap(), generics)); - } - - // Case 2. Reference to a top-level value. - Def::Fn(def_id) | - Def::Const(def_id) | - Def::Static(def_id, _) => { - fn_segment = Some((segments.last().unwrap(), self.tcx.generics_of(def_id))); - } - - // Case 3. Reference to a method or associated const. - Def::Method(def_id) | - Def::AssociatedConst(def_id) => { - let generics = self.tcx.generics_of(def_id); - if segments.len() >= 2 { - let parent_generics = self.tcx.generics_of(generics.parent.unwrap()); - type_segment = Some((&segments[segments.len() - 2], parent_generics)); - } - fn_segment = Some((segments.last().unwrap(), generics)); - } - - _ => {} - } - - debug!("type_segment={:?} fn_segment={:?}", type_segment, fn_segment); - // Now we have to compare the types that the user *actually* // provided against the types that were *expected*. If the user // did not provide any types, then we want to substitute inference @@ -5004,14 +4964,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }).unwrap_or(false); let def_id = def.def_id(); - let defs = self.tcx.generics_of(def_id); - let count = defs.count(); + let mut parent_defs = self.tcx.generics_of(def_id); + let count = parent_defs.count(); let mut substs = if count <= 8 { AccumulateVec::Array(ArrayVec::new()) } else { AccumulateVec::Heap(Vec::with_capacity(count)) }; - let mut parent_defs = defs; let mut stack = vec![(def_id, parent_defs)]; while let Some(def_id) = parent_defs.parent { parent_defs = self.tcx.generics_of(def_id); @@ -5030,7 +4989,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let infer_types = if let Some(&PathSeg(_, index)) = path_segs .iter() - .find(|&PathSeg(di, _)| *di == def_id) { + .find(|&PathSeg(did, _)| *did == def_id) { if let Some(ref data) = segments[index].args { let lifetime_offset = if infer_lifetimes[&index] { @@ -5048,7 +5007,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => bug!("expected a lifetime arg"), } GenericParamDefKind::Type { .. } => match arg { - // A provided type parameter. GenericArg::Type(ty) => self.to_ty(ty).into(), _ => bug!("expected a type arg"), } @@ -5088,15 +5046,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. - let ty = self.tcx.type_of(def.def_id()); + let ty = self.tcx.type_of(def_id); assert!(!substs.has_escaping_regions()); assert!(!ty.has_escaping_regions()); // Add all the obligations that are required, substituting and // normalized appropriately. - let bounds = self.instantiate_bounds(span, def.def_id(), &substs); + let bounds = self.instantiate_bounds(span, def_id, &substs); self.add_obligations_for_parameters( - traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())), + traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)), &bounds); // Substitute the values for the type parameters into the type of @@ -5122,7 +5080,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - self.check_rustc_args_require_const(def.def_id(), node_id, span); + self.check_rustc_args_require_const(def_id, node_id, span); debug!("instantiate_value_path: type of {:?} is {:?}", node_id, From 335770267a2ec23012b834751c2a4c9ef867b558 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 28 Jun 2018 22:13:34 +0100 Subject: [PATCH 10/41] Replace generics_require_inlining with generics.requires_monomorphization --- src/librustc/middle/reachable.rs | 21 ++++----------------- src/librustc_metadata/encoder.rs | 7 ++----- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index a09942258e22d..d49df50167287 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -34,18 +34,6 @@ use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::itemlikevisit::ItemLikeVisitor; use hir::intravisit; -// Returns true if the given set of generics implies that the item it's -// associated with must be inlined. -fn generics_require_inlining(generics: &ty::Generics) -> bool { - for param in &generics.params { - match param.kind { - GenericParamDefKind::Lifetime { .. } => {} - GenericParamDefKind::Type { .. } => return true, - } - } - false -} - // Returns true if the given item must be inlined because it may be // monomorphized or it was marked with `#[inline]`. This will only return // true for functions. @@ -60,7 +48,7 @@ fn item_might_be_inlined(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir::ItemKind::Impl(..) | hir::ItemKind::Fn(..) => { let generics = tcx.generics_of(tcx.hir.local_def_id(item.id)); - generics_require_inlining(generics) + generics.requires_monomorphization(tcx) } _ => false, } @@ -71,7 +59,7 @@ fn method_might_be_inlined<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_src: DefId) -> bool { let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id.owner_def_id()); let generics = tcx.generics_of(tcx.hir.local_def_id(impl_item.id)); - if codegen_fn_attrs.requests_inline() || generics_require_inlining(generics) { + if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) { return true } if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_src) { @@ -189,8 +177,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ImplItemKind::Method(..) => { let attrs = self.tcx.codegen_fn_attrs(def_id); let generics = self.tcx.generics_of(def_id); - if generics_require_inlining(&generics) || - attrs.requests_inline() { + if generics.requires_monomorphization(self.tcx) || attrs.requests_inline() { true } else { let impl_did = self.tcx @@ -203,7 +190,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match self.tcx.hir.expect_item(impl_node_id).node { hir::ItemKind::Impl(..) => { let generics = self.tcx.generics_of(impl_did); - generics_require_inlining(&generics) + generics.requires_monomorphization(self.tcx) } _ => false } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 3acf30a94fb24..7f07a82e31194 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1262,12 +1262,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { hir::ItemKind::Const(..) => self.encode_optimized_mir(def_id), hir::ItemKind::Fn(_, header, ..) => { let generics = tcx.generics_of(def_id); - let has_types = generics.params.iter().any(|param| match param.kind { - ty::GenericParamDefKind::Type { .. } => true, - _ => false, - }); let needs_inline = - (has_types || tcx.codegen_fn_attrs(def_id).requests_inline()) && + (generics.requires_monomorphization(tcx) || + tcx.codegen_fn_attrs(def_id).requests_inline()) && !self.metadata_output_only(); let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; if needs_inline From 734ce4ae1a87d83687d6a138f3ac78aa4bf97a8c Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 28 Jun 2018 22:29:53 +0100 Subject: [PATCH 11/41] Fix tidy check --- src/librustc/middle/reachable.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 29 +++++++++++++-------- src/librustc_typeck/check/mod.rs | 6 ++--- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index d49df50167287..3d8bb6b825b38 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -20,7 +20,7 @@ use hir::map as hir_map; use hir::def::Def; use hir::def_id::{DefId, CrateNum}; use rustc_data_structures::sync::Lrc; -use ty::{self, TyCtxt, GenericParamDefKind}; +use ty::{self, TyCtxt}; use ty::query::Providers; use middle::privacy; use session::config; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index d7d81b605c08d..d43169baf5dd3 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -316,7 +316,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // variables. let method_generics = self.tcx.generics_of(pick.item.def_id); let supress_mismatch = self.fcx.check_impl_trait(self.span, segment, &method_generics); - self.fcx.check_generic_arg_count(self.span, &segment, &method_generics, true, supress_mismatch); + self.fcx.check_generic_arg_count(self.span, &segment, &method_generics, true, + supress_mismatch); // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. @@ -324,14 +325,18 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let provided = &segment.args; let own_counts = method_generics.own_counts(); // FIXME(varkor): Separating out the parameters is messy. - let lifetimes: Vec<_> = provided.iter().flat_map(|data| data.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(ty) => Some(ty), - _ => None, - })).collect(); - let types: Vec<_> = provided.iter().flat_map(|data| data.args.iter().filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, - })).collect(); + let lifetimes: Vec<_> = provided.iter().flat_map(|data| { + data.args.iter().filter_map(|arg| match arg { + GenericArg::Lifetime(ty) => Some(ty), + _ => None, + }) + }).collect(); + let types: Vec<_> = provided.iter().flat_map(|data| { + data.args.iter().filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty), + _ => None, + }) + }).collect(); Substs::for_item(self.tcx, pick.item.def_id, |param, _| { let i = param.index as usize; if i < parent_substs.len() { @@ -339,13 +344,15 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } else { match param.kind { GenericParamDefKind::Lifetime => { - if let Some(lifetime) = lifetimes.get(i - parent_substs.len()) { + let idx = i - parent_substs.len(); + if let Some(lifetime) = lifetimes.get(idx) { return AstConv::ast_region_to_region( self.fcx, lifetime, Some(param)).into(); } } GenericParamDefKind::Type { .. } => { - if let Some(ast_ty) = types.get(i - parent_substs.len() - own_counts.lifetimes) { + let idx = i - parent_substs.len() - own_counts.lifetimes; + if let Some(ast_ty) = types.get(idx) { return self.to_ty(ast_ty).into(); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bbf41ddb81ba0..779cb6f32cd0d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5162,9 +5162,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty_accepted = ty_params.accepted; let ty_required = ty_params.required; - let count_type_params = |n| format!("{} type parameter{}", n, if n == 1 { "" } else { "s" }); - let expected_text = count_type_params(ty_accepted); - let actual_text = count_type_params(types.len()); + let count_ty_params = |n| format!("{} type parameter{}", n, if n == 1 { "" } else { "s" }); + let expected_text = count_ty_params(ty_accepted); + let actual_text = count_ty_params(types.len()); if let Some((mut err, span)) = if types.len() > ty_accepted { // To prevent derived errors to accumulate due to extra // type parameters, we force instantiate_value_path to From d5e24dc121da70027c8320ab03a7ca886d16ca0e Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 2 Jul 2018 18:09:15 +0100 Subject: [PATCH 12/41] Fix integer overflow --- src/librustc_typeck/check/mod.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 779cb6f32cd0d..916261eba226a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4997,18 +4997,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { 0 }; - let param_idx = param.index as usize - has_self as usize - lifetime_offset; + let param_idx = (param.index as usize - has_self as usize) + .saturating_sub(lifetime_offset); if let Some(arg) = data.args.get(param_idx) { - return match param.kind { + match param.kind { GenericParamDefKind::Lifetime => match arg { GenericArg::Lifetime(lt) => { - AstConv::ast_region_to_region(self, lt, Some(param)).into() + return AstConv::ast_region_to_region(self, + lt, Some(param)).into(); } - _ => bug!("expected a lifetime arg"), + _ => {} } GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => self.to_ty(ty).into(), - _ => bug!("expected a type arg"), + GenericArg::Type(ty) => return self.to_ty(ty).into(), + _ => {} } } } From d8ba103334937aacd3cc821fe75894548c40e666 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 3 Jul 2018 08:10:45 +0100 Subject: [PATCH 13/41] Fix param_idx calculation --- src/librustc_typeck/check/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 916261eba226a..c5639e9d03975 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4997,7 +4997,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { 0 }; - let param_idx = (param.index as usize - has_self as usize) + let self_offset = (defs.parent_count == 0 && has_self) as usize; + let param_idx = + (param.index as usize - defs.parent_count - self_offset as usize) .saturating_sub(lifetime_offset); if let Some(arg) = data.args.get(param_idx) { match param.kind { From b6eef180cdd47f078e9f920d7466dbdd580c2cf4 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 3 Jul 2018 09:53:46 +0100 Subject: [PATCH 14/41] Supress consecutive errors --- src/librustc_typeck/check/mod.rs | 68 ++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c5639e9d03975..87c9511019a57 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4944,11 +4944,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // to add defaults. If the user provided *too many* types, that's // a problem. let mut infer_lifetimes = FxHashMap(); + let mut supress_errors = FxHashMap(); for &PathSeg(def_id, index) in &path_segs { let seg = &segments[index]; let generics = self.tcx.generics_of(def_id); let supress_mismatch = self.check_impl_trait(span, seg, &generics); - self.check_generic_arg_count(span, seg, &generics, false, supress_mismatch); + supress_errors.insert(index, + self.check_generic_arg_count(span, seg, &generics, false, supress_mismatch)); infer_lifetimes.insert(index, if let Some(ref data) = seg.args { !data.args.iter().any(|arg| match arg { GenericArg::Lifetime(_) => true, @@ -4991,34 +4993,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .iter() .find(|&PathSeg(did, _)| *did == def_id) { - if let Some(ref data) = segments[index].args { - let lifetime_offset = if infer_lifetimes[&index] { - defs.own_counts().lifetimes - } else { - 0 - }; - let self_offset = (defs.parent_count == 0 && has_self) as usize; - let param_idx = - (param.index as usize - defs.parent_count - self_offset as usize) - .saturating_sub(lifetime_offset); - if let Some(arg) = data.args.get(param_idx) { - match param.kind { - GenericParamDefKind::Lifetime => match arg { - GenericArg::Lifetime(lt) => { - return AstConv::ast_region_to_region(self, - lt, Some(param)).into(); + if supress_errors[&index] { + true + } else { + if let Some(ref data) = segments[index].args { + let lifetime_offset = if infer_lifetimes[&index] { + defs.own_counts().lifetimes + } else { + 0 + }; + let self_offset = (defs.parent_count == 0 && has_self) as usize; + let param_idx = + (param.index as usize - defs.parent_count - self_offset as usize) + .saturating_sub(lifetime_offset); + if let Some(arg) = data.args.get(param_idx) { + match param.kind { + GenericParamDefKind::Lifetime => match arg { + GenericArg::Lifetime(lt) => { + return AstConv::ast_region_to_region(self, + lt, Some(param)).into(); + } + _ => {} + } + GenericParamDefKind::Type { .. } => match arg { + GenericArg::Type(ty) => return self.to_ty(ty).into(), + _ => {} } - _ => {} - } - GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => return self.to_ty(ty).into(), - _ => {} } } } - } - segments[index].infer_types + segments[index].infer_types + } } else { true }; @@ -5129,7 +5135,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { segment: &hir::PathSegment, generics: &ty::Generics, is_method_call: bool, - supress_mismatch_error: bool) { + supress_mismatch_error: bool) + -> bool { + let mut supress_errors = false; let (mut lifetimes, mut types) = (vec![], vec![]); let infer_types = segment.infer_types; let mut bindings = vec![]; @@ -5173,8 +5181,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // To prevent derived errors to accumulate due to extra // type parameters, we force instantiate_value_path to // use inference variables instead of the provided types. - // FIXME(varkor) - // *segment = None; + supress_errors = true; let span = types[ty_accepted].span; Some((struct_span_err!(self.tcx.sess, span, E0087, "too many type parameters provided: \ @@ -5206,18 +5213,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let note_msg = "the late bound lifetime parameter is introduced here"; if !is_method_call && (lifetimes.len() > lt_accepted || lifetimes.len() < lt_accepted && !infer_lifetimes) { + supress_errors = true; let mut err = self.tcx.sess.struct_span_err(lifetimes[0].span, primary_msg); err.span_note(span_late, note_msg); err.emit(); - // FIXME(varkor) - // *segment = None; } else { let mut multispan = MultiSpan::from_span(lifetimes[0].span); multispan.push_span_label(span_late, note_msg.to_string()); self.tcx.lint_node(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, lifetimes[0].id, multispan, primary_msg); } - return; + return supress_errors; } let count_lifetime_params = |n| { @@ -5241,6 +5247,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } { err.span_label(span, format!("expected {}", expected_text)).emit(); } + + supress_errors } /// Report error if there is an explicit type parameter when using `impl Trait`. From 84edc0a089d164ffc121d0566358718046c4a06d Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 3 Jul 2018 16:14:43 +0100 Subject: [PATCH 15/41] Move lifetime calculation outside loop --- src/librustc_typeck/check/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 87c9511019a57..8286004c2679a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4951,14 +4951,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let supress_mismatch = self.check_impl_trait(span, seg, &generics); supress_errors.insert(index, self.check_generic_arg_count(span, seg, &generics, false, supress_mismatch)); - infer_lifetimes.insert(index, if let Some(ref data) = seg.args { + let inferred_lifetimes = if if let Some(ref data) = seg.args { !data.args.iter().any(|arg| match arg { GenericArg::Lifetime(_) => true, _ => false, }) } else { true - }); + } { + generics.own_counts().lifetimes + } else { + 0 + }; + infer_lifetimes.insert(index, inferred_lifetimes); } let has_self = path_segs.last().map(|PathSeg(def_id, _)| { @@ -4997,15 +5002,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { true } else { if let Some(ref data) = segments[index].args { - let lifetime_offset = if infer_lifetimes[&index] { - defs.own_counts().lifetimes - } else { - 0 - }; let self_offset = (defs.parent_count == 0 && has_self) as usize; let param_idx = (param.index as usize - defs.parent_count - self_offset as usize) - .saturating_sub(lifetime_offset); + .saturating_sub(infer_lifetimes[&index]); if let Some(arg) = data.args.get(param_idx) { match param.kind { GenericParamDefKind::Lifetime => match arg { From 35ddd46a2d679b471b7c30bc4eb97de03396e838 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 3 Jul 2018 17:20:20 +0100 Subject: [PATCH 16/41] Refactor confirm.rs --- src/librustc_typeck/check/method/confirm.rs | 45 +++++++++------------ 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index d43169baf5dd3..aa2147e9450f6 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -322,41 +322,32 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. assert_eq!(method_generics.parent_count, parent_substs.len()); - let provided = &segment.args; - let own_counts = method_generics.own_counts(); - // FIXME(varkor): Separating out the parameters is messy. - let lifetimes: Vec<_> = provided.iter().flat_map(|data| { - data.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(ty) => Some(ty), - _ => None, - }) - }).collect(); - let types: Vec<_> = provided.iter().flat_map(|data| { - data.args.iter().filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, - }) - }).collect(); + Substs::for_item(self.tcx, pick.item.def_id, |param, _| { let i = param.index as usize; if i < parent_substs.len() { parent_substs[i] } else { - match param.kind { - GenericParamDefKind::Lifetime => { - let idx = i - parent_substs.len(); - if let Some(lifetime) = lifetimes.get(idx) { - return AstConv::ast_region_to_region( - self.fcx, lifetime, Some(param)).into(); - } - } - GenericParamDefKind::Type { .. } => { - let idx = i - parent_substs.len() - own_counts.lifetimes; - if let Some(ast_ty) = types.get(idx) { - return self.to_ty(ast_ty).into(); + let param_idx = i - parent_substs.len(); + + if let Some(ref data) = segment.args { + if let Some(arg) = data.args.get(param_idx) { + match param.kind { + GenericParamDefKind::Lifetime => match arg { + GenericArg::Lifetime(lt) => { + return AstConv::ast_region_to_region( + self.fcx, lt, Some(param)).into(); + } + _ => {} + } + GenericParamDefKind::Type { .. } => match arg { + GenericArg::Type(ty) => return self.to_ty(ty).into(), + _ => {} + } } } } + self.var_for_def(self.span, param) } }) From 340a7fc4f5c9c8c9e8526d16c8a20ff48e0b514f Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 3 Jul 2018 19:38:04 +0100 Subject: [PATCH 17/41] Refactor astconv.rs --- src/librustc_typeck/astconv.rs | 76 ++++++++++++++++++-------------- src/librustc_typeck/check/mod.rs | 4 +- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0bc7ae04185d3..18bd00d43d692 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -213,18 +213,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). - - // FIXME(varkor): Separating out the parameters is messy. - let lifetimes: Vec<_> = generic_args.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(lt) => Some(lt), - _ => None, - }).collect(); - let types: Vec<_> = generic_args.args.iter().filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, - }).collect(); - let lt_provided = lifetimes.len(); - let ty_provided = types.len(); + let mut lt_provided = 0; + let mut ty_provided = 0; + for arg in &generic_args.args { + match arg { + GenericArg::Lifetime(_) => lt_provided += 1, + GenericArg::Type(_) => ty_provided += 1, + } + } let decl_generics = tcx.generics_of(def_id); let mut lt_accepted = 0; @@ -274,30 +270,44 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { false }; - let own_self = self_ty.is_some() as usize; + let self_offset = self_ty.is_some() as usize; let substs = Substs::for_item(tcx, def_id, |param, substs| { - match param.kind { - GenericParamDefKind::Lifetime => { - let i = param.index as usize - own_self; - if let Some(lt) = lifetimes.get(i) { - self.ast_region_to_region(lt, Some(param)).into() - } else { - tcx.types.re_static.into() + if param.index == 0 { + if let Some(ty) = self_ty { + if let GenericParamDefKind::Type { .. } = param.kind { + // Handle `Self` first. + return ty.into(); } } - GenericParamDefKind::Type { has_default, .. } => { - let i = param.index as usize; + } - // Handle Self first, so we can adjust the index to match the AST. - if let (0, Some(ty)) = (i, self_ty) { - return ty.into(); + let inferred_lifetimes = if lt_provided == 0 { + lt_accepted + } else { + 0 + }; + + let param_idx = (param.index as usize - self_offset).saturating_sub(inferred_lifetimes); + + if let Some(arg) = generic_args.args.get(param_idx) { + match param.kind { + GenericParamDefKind::Lifetime => match arg { + GenericArg::Lifetime(lt) => { + return self.ast_region_to_region(lt, Some(param)).into(); + } + _ => {} + } + GenericParamDefKind::Type { .. } => match arg { + GenericArg::Type(ty) => return self.ast_ty_to_ty(ty).into(), + _ => {} } + } + } - let i = i - (lt_accepted + own_self); - if i < ty_provided { - // A provided type parameter. - self.ast_ty_to_ty(&types[i]).into() - } else if infer_types { + match param.kind { + GenericParamDefKind::Lifetime => tcx.types.re_static.into(), + GenericParamDefKind::Type { has_default, .. } => { + if infer_types { // No type parameters were provided, we can infer all. if !default_needs_object_self(param) { self.ty_infer_for_def(param, span).into() @@ -314,9 +324,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // careful! if default_needs_object_self(param) { struct_span_err!(tcx.sess, span, E0393, - "the type parameter `{}` must be explicitly \ - specified", - param.name) + "the type parameter `{}` must be explicitly \ + specified", + param.name) .span_label(span, format!("missing reference to `{}`", param.name)) .note(&format!("because of the default `Self` reference, \ diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8286004c2679a..66f5e57ef6d6e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4987,7 +4987,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Substs::fill_single(&mut substs, defs, &mut |param: &ty::GenericParamDef, substs| { if param.index == 0 && has_self { if let GenericParamDefKind::Type { .. } = param.kind { - // Handle Self first, so we can adjust the index to match the AST. + // Handle `Self` first, so we can adjust the index to match the AST. return opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| { self.var_for_def(span, param) }); @@ -5004,7 +5004,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(ref data) = segments[index].args { let self_offset = (defs.parent_count == 0 && has_self) as usize; let param_idx = - (param.index as usize - defs.parent_count - self_offset as usize) + (param.index as usize - defs.parent_count - self_offset) .saturating_sub(infer_lifetimes[&index]); if let Some(arg) = data.args.get(param_idx) { match param.kind { From e02642dbb32dff0c0c2294f6953975e3e04ef696 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 3 Jul 2018 19:55:28 +0100 Subject: [PATCH 18/41] Fix confirm.rs --- src/librustc_typeck/check/method/confirm.rs | 22 +++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index aa2147e9450f6..c9ac02928b3ba 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -323,12 +323,26 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // parameters from the type and those from the method. assert_eq!(method_generics.parent_count, parent_substs.len()); + let inferred_lifetimes = if if let Some(ref data) = segment.args { + !data.args.iter().any(|arg| match arg { + GenericArg::Lifetime(_) => true, + _ => false, + }) + } else { + true + } { + method_generics.own_counts().lifetimes + } else { + 0 + }; + Substs::for_item(self.tcx, pick.item.def_id, |param, _| { - let i = param.index as usize; - if i < parent_substs.len() { - parent_substs[i] + let param_idx = param.index as usize; + if param_idx < parent_substs.len() { + parent_substs[param_idx] } else { - let param_idx = i - parent_substs.len(); + let param_idx = (param.index as usize - parent_substs.len()) + .saturating_sub(inferred_lifetimes); if let Some(ref data) = segment.args { if let Some(arg) = data.args.get(param_idx) { From 9cfe92c8ae51caa2e7d8da7d171e59844d0a7149 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 3 Jul 2018 22:24:13 +0100 Subject: [PATCH 19/41] "Fix" annoying test --- src/test/ui/traits/trait-object-vs-lifetime.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/ui/traits/trait-object-vs-lifetime.rs b/src/test/ui/traits/trait-object-vs-lifetime.rs index a70141edc29f2..e49e516ecfe56 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.rs +++ b/src/test/ui/traits/trait-object-vs-lifetime.rs @@ -25,5 +25,4 @@ fn main() { //~| ERROR wrong number of type arguments: expected 1, found 0 let _: S<'static +, 'static>; //~^ ERROR lifetime parameters must be declared prior to type parameters - //~| ERROR at least one non-builtin trait is required for an object type } From 9bb40b09b78f650b75d22a869a8b1bf18937aba3 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 23 Jul 2018 14:48:37 +0100 Subject: [PATCH 20/41] Make prohibit_generics take IntoIterators --- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/mod.rs | 20 +++++++------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 18bd00d43d692..772ec39d8f01d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -988,7 +988,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { self.normalize_ty(span, tcx.mk_projection(item_def_id, trait_ref.substs)) } - pub fn prohibit_generics(&self, segments: &[hir::PathSegment]) { + pub fn prohibit_generics<'a, T: IntoIterator>(&self, segments: T) { for segment in segments { segment.with_generic_args(|generic_args| { let (mut err_for_lt, mut err_for_ty) = (false, false); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 66f5e57ef6d6e..c1bf6b0fe3155 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4913,19 +4913,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for PathSeg(_, index) in &path_segs { generic_segs.insert(index); } - let segs: Vec<_> = segments - .iter() - .enumerate() - .filter_map(|(index, seg)| { - if !generic_segs.contains(&index) { - Some(seg) - } else { - None - } - }) - .cloned() - .collect(); - AstConv::prohibit_generics(self, &segs); + AstConv::prohibit_generics(self, segments.iter().enumerate().filter_map(|(index, seg)| { + if !generic_segs.contains(&index) { + Some(seg) + } else { + None + } + })); match def { Def::Local(nid) | Def::Upvar(nid, ..) => { From db94efab39438278b77c990972978a7b00bdb9b9 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 23 Jul 2018 18:29:16 +0100 Subject: [PATCH 21/41] Refactor mod/check (part vii) --- src/librustc_typeck/check/mod.rs | 105 ++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 38 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c1bf6b0fe3155..fd3281d2c0ef8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,7 +95,7 @@ use rustc::infer::anon_types::AnonTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; use rustc::mir::interpret::{GlobalId}; -use rustc::ty::subst::{UnpackedKind, Subst, Substs}; +use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; @@ -4967,7 +4967,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let def_id = def.def_id(); let mut parent_defs = self.tcx.generics_of(def_id); let count = parent_defs.count(); - let mut substs = if count <= 8 { + let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 { AccumulateVec::Array(ArrayVec::new()) } else { AccumulateVec::Heap(Vec::with_capacity(count)) @@ -4977,74 +4977,103 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { parent_defs = self.tcx.generics_of(def_id); stack.push((def_id, parent_defs)); } + macro_rules! push_to_substs { + ($kind:expr) => { + let k = $kind; + match substs { + AccumulateVec::Array(ref mut arr) => arr.push(k), + AccumulateVec::Heap(ref mut vec) => vec.push(k), + } + } + }; while let Some((def_id, defs)) = stack.pop() { - Substs::fill_single(&mut substs, defs, &mut |param: &ty::GenericParamDef, substs| { - if param.index == 0 && has_self { - if let GenericParamDefKind::Type { .. } = param.kind { - // Handle `Self` first, so we can adjust the index to match the AST. - return opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| { - self.var_for_def(span, param) - }); + let mut params = defs.params.iter().peekable(); + let mut remove_self = false; + if has_self { + if let Some(param) = params.peek() { + if param.index == 0 { + if let GenericParamDefKind::Type { .. } = param.kind { + // Handle `Self` first, so we can adjust the index to match the AST. + push_to_substs!(opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| { + self.var_for_def(span, param) + })); + remove_self = true; + } } } + } + if remove_self { + params.next(); + } - let infer_types = if let Some(&PathSeg(_, index)) = path_segs - .iter() - .find(|&PathSeg(did, _)| *did == def_id) { - - if supress_errors[&index] { - true - } else { - if let Some(ref data) = segments[index].args { - let self_offset = (defs.parent_count == 0 && has_self) as usize; - let param_idx = - (param.index as usize - defs.parent_count - self_offset) - .saturating_sub(infer_lifetimes[&index]); - if let Some(arg) = data.args.get(param_idx) { + let mut infer_types = true; + if let Some(&PathSeg(_, index)) = path_segs + .iter() + .find(|&PathSeg(did, _)| *did == def_id) { + if !supress_errors[&index] { + infer_types = segments[index].infer_types; + if let Some(ref data) = segments[index].args { + let args = &data.args; + 'args: for arg in args { + while let Some(param) = params.next() { match param.kind { GenericParamDefKind::Lifetime => match arg { GenericArg::Lifetime(lt) => { - return AstConv::ast_region_to_region(self, - lt, Some(param)).into(); + push_to_substs!(AstConv::ast_region_to_region(self, + lt, Some(param)).into()); + continue 'args; + } + GenericArg::Type(_) => { + // We're inferring a lifetime. + push_to_substs!( + self.re_infer(span, Some(param)).unwrap().into()); } - _ => {} } GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => return self.to_ty(ty).into(), - _ => {} + GenericArg::Type(ty) => { + push_to_substs!(self.to_ty(ty).into()); + continue 'args; + } + GenericArg::Lifetime(_) => { + self.tcx.sess.delay_span_bug(span, + "found a GenericArg::Lifetime where a \ + GenericArg::Type was expected"); + } } } } + // If we get to this point, we have a GenericArg that is not matched + // by a GenericParamDef: i.e. the user supplied too many generic args. + self.tcx.sess.delay_span_bug(span, + "GenericArg did not have matching GenericParamDef"); } - - segments[index].infer_types } - } else { - true - }; + } + } + while let Some(param) = params.next() { match param.kind { GenericParamDefKind::Lifetime => { - self.re_infer(span, Some(param)).unwrap().into() + push_to_substs!(self.re_infer(span, Some(param)).unwrap().into()); } GenericParamDefKind::Type { has_default, .. } => { if !infer_types && has_default { // No type parameter provided, but a default exists. let default = self.tcx.type_of(param.def_id); - self.normalize_ty( + push_to_substs!(self.normalize_ty( span, - default.subst_spanned(self.tcx, substs, Some(span)) - ).into() + default.subst_spanned(self.tcx, &substs, Some(span)) + ).into()); } else { // No type parameters were provided, we can infer all. // This can also be reached in some error cases: // We prefer to use inference variables instead of // TyError to let type inference recover somewhat. - self.var_for_def(span, param) + push_to_substs!(self.var_for_def(span, param)); } } } - }); + } } let substs = self.tcx.intern_substs(&substs); From 5f2588f020c3da7b1d5c6ec089b833ca424ad403 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 23 Jul 2018 23:55:24 +0100 Subject: [PATCH 22/41] Fix behaviour in error condition --- src/librustc_typeck/check/mod.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fd3281d2c0ef8..647e7b4a70f4b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4987,24 +4987,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; while let Some((def_id, defs)) = stack.pop() { - let mut params = defs.params.iter().peekable(); - let mut remove_self = false; + let mut params = defs.params.iter(); + let mut next_param = params.next(); if has_self { - if let Some(param) = params.peek() { + if let Some(param) = next_param { if param.index == 0 { if let GenericParamDefKind::Type { .. } = param.kind { // Handle `Self` first, so we can adjust the index to match the AST. push_to_substs!(opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| { self.var_for_def(span, param) })); - remove_self = true; + next_param = params.next(); } } } } - if remove_self { - params.next(); - } let mut infer_types = true; if let Some(&PathSeg(_, index)) = path_segs @@ -5015,29 +5012,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(ref data) = segments[index].args { let args = &data.args; 'args: for arg in args { - while let Some(param) = params.next() { + while let Some(param) = next_param { match param.kind { GenericParamDefKind::Lifetime => match arg { GenericArg::Lifetime(lt) => { push_to_substs!(AstConv::ast_region_to_region(self, lt, Some(param)).into()); + next_param = params.next(); continue 'args; } GenericArg::Type(_) => { // We're inferring a lifetime. push_to_substs!( self.re_infer(span, Some(param)).unwrap().into()); + next_param = params.next(); } } GenericParamDefKind::Type { .. } => match arg { GenericArg::Type(ty) => { push_to_substs!(self.to_ty(ty).into()); + next_param = params.next(); continue 'args; } GenericArg::Lifetime(_) => { self.tcx.sess.delay_span_bug(span, "found a GenericArg::Lifetime where a \ GenericArg::Type was expected"); + break 'args; } } } @@ -5051,7 +5052,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - while let Some(param) = params.next() { + while let Some(param) = next_param { match param.kind { GenericParamDefKind::Lifetime => { push_to_substs!(self.re_infer(span, Some(param)).unwrap().into()); @@ -5073,6 +5074,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } + next_param = params.next(); } } let substs = self.tcx.intern_substs(&substs); From 08d49a65e72c955f39b653a94a9013f11d328d21 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 24 Jul 2018 01:43:30 +0100 Subject: [PATCH 23/41] Refactor mod/check (part viii) --- src/librustc/ty/subst.rs | 8 +-- src/librustc_typeck/check/mod.rs | 112 ++++++++++++++++++------------- 2 files changed, 69 insertions(+), 51 deletions(-) diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 0bee400f449fe..a6ff979f472af 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -226,9 +226,9 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } fn fill_item(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - defs: &ty::Generics, - mk_kind: &mut F) + tcx: TyCtxt<'a, 'gcx, 'tcx>, + defs: &ty::Generics, + mk_kind: &mut F) where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx> { if let Some(def_id) = defs.parent { @@ -238,7 +238,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { Substs::fill_single(substs, defs, mk_kind) } - pub fn fill_single(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, + fn fill_single(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, defs: &ty::Generics, mk_kind: &mut F) where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx> diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 647e7b4a70f4b..1ef296774ea83 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4909,6 +4909,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // segment belong to, let's sort out the parameters that the user // provided (if any) into their appropriate spaces. We'll also report // errors if type parameters are provided in an inappropriate place. + let mut generic_segs = HashSet::new(); for PathSeg(_, index) in &path_segs { generic_segs.insert(index); @@ -4937,66 +4938,62 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // variables. If the user provided some types, we may still need // to add defaults. If the user provided *too many* types, that's // a problem. - let mut infer_lifetimes = FxHashMap(); + let mut supress_errors = FxHashMap(); for &PathSeg(def_id, index) in &path_segs { let seg = &segments[index]; let generics = self.tcx.generics_of(def_id); + // `impl Trait` is treated as a normal generic parameter internally, + // but we don't allow users to specify the parameter's value + // explicitly, so we have to do some error-checking here. let supress_mismatch = self.check_impl_trait(span, seg, &generics); supress_errors.insert(index, self.check_generic_arg_count(span, seg, &generics, false, supress_mismatch)); - let inferred_lifetimes = if if let Some(ref data) = seg.args { - !data.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }) - } else { - true - } { - generics.own_counts().lifetimes - } else { - 0 - }; - infer_lifetimes.insert(index, inferred_lifetimes); } let has_self = path_segs.last().map(|PathSeg(def_id, _)| { self.tcx.generics_of(*def_id).has_self }).unwrap_or(false); + // Collect the segments of the path: we need to substitute arguments + // for parameters throughout the entire path (wherever there are + // generic parameters). let def_id = def.def_id(); let mut parent_defs = self.tcx.generics_of(def_id); let count = parent_defs.count(); - let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 { - AccumulateVec::Array(ArrayVec::new()) - } else { - AccumulateVec::Heap(Vec::with_capacity(count)) - }; let mut stack = vec![(def_id, parent_defs)]; while let Some(def_id) = parent_defs.parent { parent_defs = self.tcx.generics_of(def_id); stack.push((def_id, parent_defs)); } - macro_rules! push_to_substs { - ($kind:expr) => { - let k = $kind; - match substs { - AccumulateVec::Array(ref mut arr) => arr.push(k), - AccumulateVec::Heap(ref mut vec) => vec.push(k), - } - } + + // We manually build up the substitution, rather than using convenience + // methods in subst.rs so that we can iterate over the arguments and + // parameters in lock-step linearly, rather than trying to match each pair. + let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 { + AccumulateVec::Array(ArrayVec::new()) + } else { + AccumulateVec::Heap(Vec::with_capacity(count)) }; + fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) { + match substs { + AccumulateVec::Array(ref mut arr) => arr.push(kind), + AccumulateVec::Heap(ref mut vec) => vec.push(kind), + } + } + + // Iterate over each segment of the path. while let Some((def_id, defs)) = stack.pop() { let mut params = defs.params.iter(); let mut next_param = params.next(); + + // `Self` is handled first. if has_self { if let Some(param) = next_param { if param.index == 0 { if let GenericParamDefKind::Type { .. } = param.kind { - // Handle `Self` first, so we can adjust the index to match the AST. - push_to_substs!(opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| { - self.var_for_def(span, param) - })); + push_kind(&mut substs, opt_self_ty.map(|ty| ty.into()) + .unwrap_or_else(|| self.var_for_def(span, param))); next_param = params.next(); } } @@ -5004,37 +5001,52 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let mut infer_types = true; + // Check whether this segment takes generic arguments. if let Some(&PathSeg(_, index)) = path_segs .iter() .find(|&PathSeg(did, _)| *did == def_id) { + // If we've encountered an `impl Trait`-related error, we're just + // going to infer the arguments for better error messages. if !supress_errors[&index] { infer_types = segments[index].infer_types; + // Check whether the user has provided generic arguments. if let Some(ref data) = segments[index].args { let args = &data.args; + // We're going to iterate through the generic arguments that the user + // provided, matching them with the generic parameters we expect. + // Mismatches can occur as a result of elided lifetimes, or for malformed + // input. We try to handle both sensibly. 'args: for arg in args { while let Some(param) = next_param { match param.kind { GenericParamDefKind::Lifetime => match arg { GenericArg::Lifetime(lt) => { - push_to_substs!(AstConv::ast_region_to_region(self, - lt, Some(param)).into()); + push_kind(&mut substs, + AstConv::ast_region_to_region(self, lt, Some(param)) + .into()); next_param = params.next(); continue 'args; } GenericArg::Type(_) => { - // We're inferring a lifetime. - push_to_substs!( + // We expected a lifetime argument, but got a type + // argument. That means we're inferring the lifetimes. + push_kind(&mut substs, self.re_infer(span, Some(param)).unwrap().into()); next_param = params.next(); } } GenericParamDefKind::Type { .. } => match arg { GenericArg::Type(ty) => { - push_to_substs!(self.to_ty(ty).into()); + push_kind(&mut substs, self.to_ty(ty).into()); next_param = params.next(); continue 'args; } GenericArg::Lifetime(_) => { + // We expected a type argument, but got a lifetime + // argument. This is an error, but we need to handle it + // gracefully so we can report sensible errors. In this + // case, we're simply going to infer the remaining + // arguments. self.tcx.sess.delay_span_bug(span, "found a GenericArg::Lifetime where a \ GenericArg::Type was expected"); @@ -5043,8 +5055,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - // If we get to this point, we have a GenericArg that is not matched - // by a GenericParamDef: i.e. the user supplied too many generic args. + // We should never be able to reach this point with well-formed input. + // Getting to this point means the user supplied more arguments than + // there are parameters. self.tcx.sess.delay_span_bug(span, "GenericArg did not have matching GenericParamDef"); } @@ -5052,25 +5065,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + // If there are fewer arguments than parameters, it means + // we're inferring the remaining arguments. while let Some(param) = next_param { match param.kind { GenericParamDefKind::Lifetime => { - push_to_substs!(self.re_infer(span, Some(param)).unwrap().into()); + push_kind(&mut substs, self.re_infer(span, Some(param)).unwrap().into()); } GenericParamDefKind::Type { has_default, .. } => { if !infer_types && has_default { - // No type parameter provided, but a default exists. + // If we have a default, then we it doesn't matter that we're not + // inferring the type arguments: we provide the default where any + // is missing. let default = self.tcx.type_of(param.def_id); - push_to_substs!(self.normalize_ty( + let kind = self.normalize_ty( span, default.subst_spanned(self.tcx, &substs, Some(span)) - ).into()); + ).into(); + push_kind(&mut substs, kind); } else { - // No type parameters were provided, we can infer all. - // This can also be reached in some error cases: - // We prefer to use inference variables instead of - // TyError to let type inference recover somewhat. - push_to_substs!(self.var_for_def(span, param)); + // If no type arguments were provided, we have to infer them. + // This case also occurs as a result of some malformed input, e.g. + // a lifetime argument being given instead of a type paramter. + // Using inference instead of `TyError` gives better error messages. + push_kind(&mut substs, self.var_for_def(span, param)); } } } From 5d07db436db3a3c1bf3e3940423ee91d2ca368c7 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 24 Jul 2018 02:27:18 +0100 Subject: [PATCH 24/41] Refactor confirm.rs (part ii) --- src/librustc_typeck/check/method/confirm.rs | 94 +++++++++++++++------ 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index c9ac02928b3ba..401e57f315764 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -14,7 +14,7 @@ use astconv::AstConv; use check::{FnCtxt, PlaceOp, callee, Needs}; use hir::GenericArg; use hir::def_id::DefId; -use rustc::ty::subst::Substs; +use rustc::ty::subst::{Kind, Substs}; use rustc::traits; use rustc::ty::{self, Ty, GenericParamDefKind}; use rustc::ty::subst::Subst; @@ -24,6 +24,8 @@ use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk}; use syntax_pos::Span; use rustc::hir; +use rustc_data_structures::accumulate_vec::AccumulateVec; +use rustc_data_structures::array_vec::ArrayVec; use std::ops::Deref; @@ -323,48 +325,86 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // parameters from the type and those from the method. assert_eq!(method_generics.parent_count, parent_substs.len()); - let inferred_lifetimes = if if let Some(ref data) = segment.args { - !data.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }) - } else { - true - } { - method_generics.own_counts().lifetimes + // Collect the segments of the path: we need to substitute arguments + // for parameters throughout the entire path (wherever there are + // generic parameters). + let def_id = pick.item.def_id; + let mut parent_defs = self.tcx.generics_of(def_id); + let count = parent_defs.count(); + let mut stack = vec![(def_id, parent_defs)]; + while let Some(def_id) = parent_defs.parent { + parent_defs = self.tcx.generics_of(def_id); + stack.push((def_id, parent_defs)); + } + + // We manually build up the substitution, rather than using convenience + // methods in subst.rs so that we can iterate over the arguments and + // parameters in lock-step linearly, rather than trying to match each pair. + let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 { + AccumulateVec::Array(ArrayVec::new()) } else { - 0 + AccumulateVec::Heap(Vec::with_capacity(count)) }; + fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) { + match substs { + AccumulateVec::Array(ref mut arr) => arr.push(kind), + AccumulateVec::Heap(ref mut vec) => vec.push(kind), + } + } - Substs::for_item(self.tcx, pick.item.def_id, |param, _| { - let param_idx = param.index as usize; - if param_idx < parent_substs.len() { - parent_substs[param_idx] - } else { - let param_idx = (param.index as usize - parent_substs.len()) - .saturating_sub(inferred_lifetimes); + // Iterate over each segment of the path. + while let Some((_, defs)) = stack.pop() { + let mut params = defs.params.iter(); + let mut next_param = params.next(); + + while let Some(param) = next_param { + if let Some(&kind) = parent_substs.get(param.index as usize) { + push_kind(&mut substs, kind); + next_param = params.next(); + } else { + break; + } + } - if let Some(ref data) = segment.args { - if let Some(arg) = data.args.get(param_idx) { + if let Some(ref data) = segment.args { + let args = &data.args; + 'args: for arg in args { + while let Some(param) = next_param { match param.kind { GenericParamDefKind::Lifetime => match arg { GenericArg::Lifetime(lt) => { - return AstConv::ast_region_to_region( - self.fcx, lt, Some(param)).into(); + push_kind(&mut substs, AstConv::ast_region_to_region( + self.fcx, lt, Some(param)).into()); + next_param = params.next(); + continue 'args; + } + _ => { + push_kind(&mut substs, self.var_for_def(self.span, param)); + next_param = params.next(); } - _ => {} } GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => return self.to_ty(ty).into(), - _ => {} + GenericArg::Type(ty) => { + push_kind(&mut substs, self.to_ty(ty).into()); + next_param = params.next(); + continue 'args; + } + _ => { + break 'args; + } } } } } + } - self.var_for_def(self.span, param) + while let Some(param) = next_param { + push_kind(&mut substs, self.var_for_def(self.span, param)); + next_param = params.next(); } - }) + } + + self.tcx.intern_substs(&substs) } fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) { From b524991f0383abe85f93d5a2e90565189034f175 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 24 Jul 2018 02:59:22 +0100 Subject: [PATCH 25/41] Refactor astconv.rs (part ii) --- src/librustc_typeck/astconv.rs | 183 ++++++++++++++++++++----------- src/test/ui/error-codes/E0107.rs | 3 +- 2 files changed, 117 insertions(+), 69 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 772ec39d8f01d..ccea902e4b601 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -13,12 +13,13 @@ //! is parameterized by an instance of `AstConv`. use rustc_data_structures::accumulate_vec::AccumulateVec; +use rustc_data_structures::array_vec::ArrayVec; use hir::{self, GenericArg}; use hir::def::Def; use hir::def_id::DefId; use middle::resolve_lifetime as rl; use namespace::Namespace; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::GenericParamDefKind; @@ -270,85 +271,133 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { false }; - let self_offset = self_ty.is_some() as usize; - let substs = Substs::for_item(tcx, def_id, |param, substs| { - if param.index == 0 { - if let Some(ty) = self_ty { - if let GenericParamDefKind::Type { .. } = param.kind { - // Handle `Self` first. - return ty.into(); + // Collect the segments of the path: we need to substitute arguments + // for parameters throughout the entire path (wherever there are + // generic parameters). + let mut parent_defs = self.tcx().generics_of(def_id); + let count = parent_defs.count(); + let mut stack = vec![(def_id, parent_defs)]; + while let Some(def_id) = parent_defs.parent { + parent_defs = self.tcx().generics_of(def_id); + stack.push((def_id, parent_defs)); + } + + // We manually build up the substitution, rather than using convenience + // methods in subst.rs so that we can iterate over the arguments and + // parameters in lock-step linearly, rather than trying to match each pair. + let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 { + AccumulateVec::Array(ArrayVec::new()) + } else { + AccumulateVec::Heap(Vec::with_capacity(count)) + }; + fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) { + match substs { + AccumulateVec::Array(ref mut arr) => arr.push(kind), + AccumulateVec::Heap(ref mut vec) => vec.push(kind), + } + } + + // Iterate over each segment of the path. + while let Some((_, defs)) = stack.pop() { + let mut params = defs.params.iter(); + let mut next_param = params.next(); + + // `Self` is handled first. + if let Some(ty) = self_ty { + if let Some(param) = next_param { + if param.index == 0 { + if let GenericParamDefKind::Type { .. } = param.kind { + push_kind(&mut substs, ty.into()); + next_param = params.next(); + } } } } - let inferred_lifetimes = if lt_provided == 0 { - lt_accepted - } else { - 0 - }; - - let param_idx = (param.index as usize - self_offset).saturating_sub(inferred_lifetimes); - - if let Some(arg) = generic_args.args.get(param_idx) { - match param.kind { - GenericParamDefKind::Lifetime => match arg { - GenericArg::Lifetime(lt) => { - return self.ast_region_to_region(lt, Some(param)).into(); + let args = &generic_args.args; + 'args: for arg in args { + while let Some(param) = next_param { + match param.kind { + GenericParamDefKind::Lifetime => match arg { + GenericArg::Lifetime(lt) => { + push_kind(&mut substs, + self.ast_region_to_region(<, Some(param)).into()); + next_param = params.next(); + continue 'args; + } + GenericArg::Type(_) => { + // We expected a lifetime argument, but got a type + // argument. That means we're inferring the lifetimes. + push_kind(&mut substs, tcx.types.re_static.into()); + next_param = params.next(); + } + } + GenericParamDefKind::Type { .. } => match arg { + GenericArg::Type(ty) => { + push_kind(&mut substs, self.ast_ty_to_ty(&ty).into()); + next_param = params.next(); + continue 'args; + } + GenericArg::Lifetime(_) => { + break 'args; + } } - _ => {} - } - GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => return self.ast_ty_to_ty(ty).into(), - _ => {} } } } - match param.kind { - GenericParamDefKind::Lifetime => tcx.types.re_static.into(), - GenericParamDefKind::Type { has_default, .. } => { - if infer_types { - // No type parameters were provided, we can infer all. - if !default_needs_object_self(param) { - self.ty_infer_for_def(param, span).into() - } else { - self.ty_infer(span).into() - } - } else if has_default { - // No type parameter provided, but a default exists. - - // If we are converting an object type, then the - // `Self` parameter is unknown. However, some of the - // other type parameters may reference `Self` in their - // defaults. This will lead to an ICE if we are not - // careful! - if default_needs_object_self(param) { - struct_span_err!(tcx.sess, span, E0393, - "the type parameter `{}` must be explicitly \ - specified", - param.name) - .span_label(span, - format!("missing reference to `{}`", param.name)) - .note(&format!("because of the default `Self` reference, \ - type parameters must be specified on object \ - types")) - .emit(); - tcx.types.err.into() + while let Some(param) = next_param { + match param.kind { + GenericParamDefKind::Lifetime => { + push_kind(&mut substs, tcx.types.re_static.into()); + } + GenericParamDefKind::Type { has_default, .. } => { + if infer_types { + // No type parameters were provided, we can infer all. + push_kind(&mut substs, if !default_needs_object_self(param) { + self.ty_infer_for_def(param, span).into() + } else { + self.ty_infer(span).into() + }); + } else if has_default { + // No type parameter provided, but a default exists. + + // If we are converting an object type, then the + // `Self` parameter is unknown. However, some of the + // other type parameters may reference `Self` in their + // defaults. This will lead to an ICE if we are not + // careful! + if default_needs_object_self(param) { + struct_span_err!(tcx.sess, span, E0393, + "the type parameter `{}` must be explicitly \ + specified", + param.name) + .span_label(span, + format!("missing reference to `{}`", param.name)) + .note(&format!("because of the default `Self` reference, \ + type parameters must be specified on object \ + types")) + .emit(); + push_kind(&mut substs, tcx.types.err.into()); + } else { + // This is a default type parameter. + let kind = self.normalize_ty( + span, + tcx.at(span).type_of(param.def_id) + .subst_spanned(tcx, &substs, Some(span)) + ).into(); + push_kind(&mut substs, kind); + } } else { - // This is a default type parameter. - self.normalize_ty( - span, - tcx.at(span).type_of(param.def_id) - .subst_spanned(tcx, substs, Some(span)) - ).into() + // We've already errored above about the mismatch. + push_kind(&mut substs, tcx.types.err.into()); } - } else { - // We've already errored above about the mismatch. - tcx.types.err.into() } - } + }; + next_param = params.next(); } - }); + } + let substs = self.tcx().intern_substs(&substs); let assoc_bindings = generic_args.bindings.iter().map(|binding| { ConvertedBinding { diff --git a/src/test/ui/error-codes/E0107.rs b/src/test/ui/error-codes/E0107.rs index 16ebd3e9ca5f2..3b0eedae14c1d 100644 --- a/src/test/ui/error-codes/E0107.rs +++ b/src/test/ui/error-codes/E0107.rs @@ -29,5 +29,4 @@ struct Baz<'a, 'b, 'c> { //~| 2 unexpected lifetime parameters } -fn main() { -} +fn main() {} From ccef306b965697f01a5eb9fb69b9b7a34517cc8a Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 24 Jul 2018 13:23:45 +0100 Subject: [PATCH 26/41] Revert broken test --- src/test/ui/traits/trait-object-vs-lifetime.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/traits/trait-object-vs-lifetime.rs b/src/test/ui/traits/trait-object-vs-lifetime.rs index e49e516ecfe56..a70141edc29f2 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.rs +++ b/src/test/ui/traits/trait-object-vs-lifetime.rs @@ -25,4 +25,5 @@ fn main() { //~| ERROR wrong number of type arguments: expected 1, found 0 let _: S<'static +, 'static>; //~^ ERROR lifetime parameters must be declared prior to type parameters + //~| ERROR at least one non-builtin trait is required for an object type } From e79bc410bf5f8d07121cc685d611ca72c21b28d0 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 24 Jul 2018 17:47:31 +0100 Subject: [PATCH 27/41] Consolidate into create_substs_for_generic_args --- src/librustc_typeck/astconv.rs | 285 +++++++++++++------- src/librustc_typeck/check/method/confirm.rs | 109 +++----- src/librustc_typeck/check/mod.rs | 169 ++++-------- 3 files changed, 268 insertions(+), 295 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ccea902e4b601..83c18265489f3 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -14,7 +14,7 @@ use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::array_vec::ArrayVec; -use hir::{self, GenericArg}; +use hir::{self, GenericArg, GenericArgs}; use hir::def::Def; use hir::def_id::DefId; use middle::resolve_lifetime as rl; @@ -22,7 +22,7 @@ use namespace::Namespace; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; -use rustc::ty::GenericParamDefKind; +use rustc::ty::{GenericParamDef, GenericParamDefKind}; use rustc::ty::wf::object_region_bounds; use rustc_target::spec::abi; use std::slice; @@ -192,6 +192,153 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { substs } + /// Creates the relevant generic argument substitutions + /// corresponding to a set of generic parameters. + pub fn create_substs_for_generic_args<'a, 'b, A, P, I>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + span: Span, + err_if_invalid: bool, + def_id: DefId, + parent_substs: &[Kind<'tcx>], + has_self: bool, + self_ty: Option>, + args_for_def_id: A, + provided_kind: P, + inferred_kind: I, + ) -> &'tcx Substs<'tcx> where + A: Fn(DefId) -> (Option<&'b GenericArgs>, bool), + P: Fn(&GenericParamDef, &GenericArg) -> Kind<'tcx>, + I: Fn(Option<&[Kind<'tcx>]>, &GenericParamDef, bool) -> Kind<'tcx> + { + // Collect the segments of the path: we need to substitute arguments + // for parameters throughout the entire path (wherever there are + // generic parameters). + let mut parent_defs = tcx.generics_of(def_id); + let count = parent_defs.count(); + let mut stack = vec![(def_id, parent_defs)]; + while let Some(def_id) = parent_defs.parent { + parent_defs = tcx.generics_of(def_id); + stack.push((def_id, parent_defs)); + } + + // We manually build up the substitution, rather than using convenience + // methods in subst.rs so that we can iterate over the arguments and + // parameters in lock-step linearly, rather than trying to match each pair. + let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 { + AccumulateVec::Array(ArrayVec::new()) + } else { + AccumulateVec::Heap(Vec::with_capacity(count)) + }; + + fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) { + match substs { + AccumulateVec::Array(ref mut arr) => arr.push(kind), + AccumulateVec::Heap(ref mut vec) => vec.push(kind), + } + } + + // Iterate over each segment of the path. + while let Some((def_id, defs)) = stack.pop() { + let mut params = defs.params.iter(); + let mut next_param = params.next(); + + // If we have already computed substitutions for parents, we can use those directly. + while let Some(param) = next_param { + if let Some(&kind) = parent_substs.get(param.index as usize) { + push_kind(&mut substs, kind); + next_param = params.next(); + } else { + break; + } + } + + // (Unless it's been handled in `parent_substs`) `Self` is handled first. + if has_self { + if let Some(param) = next_param { + if param.index == 0 { + if let GenericParamDefKind::Type { .. } = param.kind { + push_kind(&mut substs, self_ty.map(|ty| ty.into()) + .unwrap_or_else(|| inferred_kind(None, param, true))); + next_param = params.next(); + } + } + } + } + + // Check whether this segment takes generic arguments and the user has provided any. + let (generic_args, infer_types) = args_for_def_id(def_id); + if let Some(ref generic_args) = generic_args { + // We're going to iterate through the generic arguments that the user + // provided, matching them with the generic parameters we expect. + // Mismatches can occur as a result of elided lifetimes, or for malformed + // input. We try to handle both sensibly. + 'args: for arg in &generic_args.args { + while let Some(param) = next_param { + match param.kind { + GenericParamDefKind::Lifetime => match arg { + GenericArg::Lifetime(_) => { + push_kind(&mut substs, provided_kind(param, arg)); + next_param = params.next(); + continue 'args; + } + GenericArg::Type(_) => { + // We expected a lifetime argument, but got a type + // argument. That means we're inferring the lifetimes. + push_kind(&mut substs, inferred_kind(None, param, infer_types)); + next_param = params.next(); + } + } + GenericParamDefKind::Type { .. } => match arg { + GenericArg::Type(_) => { + push_kind(&mut substs, provided_kind(param, arg)); + next_param = params.next(); + continue 'args; + } + GenericArg::Lifetime(_) => { + // We expected a type argument, but got a lifetime + // argument. This is an error, but we need to handle it + // gracefully so we can report sensible errors. In this + // case, we're simply going to infer the remaining + // arguments. + if err_if_invalid { + tcx.sess.delay_span_bug(span, + "found a GenericArg::Lifetime where a \ + GenericArg::Type was expected"); + } + break 'args; + } + } + } + } + // We should never be able to reach this point with well-formed input. + // Getting to this point means the user supplied more arguments than + // there are parameters. + if err_if_invalid { + tcx.sess.delay_span_bug(span, + "GenericArg did not have matching GenericParamDef"); + } + } + } + + // If there are fewer arguments than parameters, it means + // we're inferring the remaining arguments. + while let Some(param) = next_param { + match param.kind { + GenericParamDefKind::Lifetime => { + push_kind(&mut substs, inferred_kind(None, param, infer_types)); + } + GenericParamDefKind::Type { .. } => { + let kind = inferred_kind(Some(&substs), param, infer_types); + push_kind(&mut substs, kind); + } + } + next_param = params.next(); + } + } + + tcx.intern_substs(&substs) + } + /// Given the type/region arguments provided to some path (along with /// an implicit Self, if this is a trait reference) returns the complete /// set of substitutions. This may involve applying defaulted type parameters. @@ -271,95 +418,37 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { false }; - // Collect the segments of the path: we need to substitute arguments - // for parameters throughout the entire path (wherever there are - // generic parameters). - let mut parent_defs = self.tcx().generics_of(def_id); - let count = parent_defs.count(); - let mut stack = vec![(def_id, parent_defs)]; - while let Some(def_id) = parent_defs.parent { - parent_defs = self.tcx().generics_of(def_id); - stack.push((def_id, parent_defs)); - } - - // We manually build up the substitution, rather than using convenience - // methods in subst.rs so that we can iterate over the arguments and - // parameters in lock-step linearly, rather than trying to match each pair. - let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 { - AccumulateVec::Array(ArrayVec::new()) - } else { - AccumulateVec::Heap(Vec::with_capacity(count)) - }; - fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) { - match substs { - AccumulateVec::Array(ref mut arr) => arr.push(kind), - AccumulateVec::Heap(ref mut vec) => vec.push(kind), - } - } - - // Iterate over each segment of the path. - while let Some((_, defs)) = stack.pop() { - let mut params = defs.params.iter(); - let mut next_param = params.next(); - - // `Self` is handled first. - if let Some(ty) = self_ty { - if let Some(param) = next_param { - if param.index == 0 { - if let GenericParamDefKind::Type { .. } = param.kind { - push_kind(&mut substs, ty.into()); - next_param = params.next(); + let substs = Self::create_substs_for_generic_args( + self.tcx(), + span, + false, + def_id, + &[][..], + self_ty.is_some(), + self_ty, + // Provide the generic args, and whether types should be inferred. + |_| (Some(generic_args), infer_types), + // Provide substitutions for parameters for which (valid) arguments have been provided. + |param, arg| { + match param.kind { + GenericParamDefKind::Lifetime => match arg { + GenericArg::Lifetime(lt) => { + self.ast_region_to_region(<, Some(param)).into() } + _ => unreachable!(), } - } - } - - let args = &generic_args.args; - 'args: for arg in args { - while let Some(param) = next_param { - match param.kind { - GenericParamDefKind::Lifetime => match arg { - GenericArg::Lifetime(lt) => { - push_kind(&mut substs, - self.ast_region_to_region(<, Some(param)).into()); - next_param = params.next(); - continue 'args; - } - GenericArg::Type(_) => { - // We expected a lifetime argument, but got a type - // argument. That means we're inferring the lifetimes. - push_kind(&mut substs, tcx.types.re_static.into()); - next_param = params.next(); - } - } - GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => { - push_kind(&mut substs, self.ast_ty_to_ty(&ty).into()); - next_param = params.next(); - continue 'args; - } - GenericArg::Lifetime(_) => { - break 'args; - } - } + GenericParamDefKind::Type { .. } => match arg { + GenericArg::Type(ty) => self.ast_ty_to_ty(&ty).into(), + _ => unreachable!(), } } - } - - while let Some(param) = next_param { + }, + // Provide substitutions for parameters for which arguments are inferred. + |substs, param, infer_types| { match param.kind { - GenericParamDefKind::Lifetime => { - push_kind(&mut substs, tcx.types.re_static.into()); - } + GenericParamDefKind::Lifetime => tcx.types.re_static.into(), GenericParamDefKind::Type { has_default, .. } => { - if infer_types { - // No type parameters were provided, we can infer all. - push_kind(&mut substs, if !default_needs_object_self(param) { - self.ty_infer_for_def(param, span).into() - } else { - self.ty_infer(span).into() - }); - } else if has_default { + if !infer_types && has_default { // No type parameter provided, but a default exists. // If we are converting an object type, then the @@ -378,26 +467,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { type parameters must be specified on object \ types")) .emit(); - push_kind(&mut substs, tcx.types.err.into()); + tcx.types.err.into() } else { // This is a default type parameter. - let kind = self.normalize_ty( + self.normalize_ty( span, tcx.at(span).type_of(param.def_id) - .subst_spanned(tcx, &substs, Some(span)) - ).into(); - push_kind(&mut substs, kind); + .subst_spanned(tcx, substs.unwrap(), Some(span)) + ).into() + } + } else if infer_types { + // No type parameters were provided, we can infer all. + if !default_needs_object_self(param) { + self.ty_infer_for_def(param, span).into() + } else { + self.ty_infer(span).into() } } else { // We've already errored above about the mismatch. - push_kind(&mut substs, tcx.types.err.into()); + tcx.types.err.into() } } - }; - next_param = params.next(); - } - } - let substs = self.tcx().intern_substs(&substs); + } + }, + ); let assoc_bindings = generic_args.bindings.iter().map(|binding| { ConvertedBinding { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 401e57f315764..0acbd8031035d 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -14,7 +14,7 @@ use astconv::AstConv; use check::{FnCtxt, PlaceOp, callee, Needs}; use hir::GenericArg; use hir::def_id::DefId; -use rustc::ty::subst::{Kind, Substs}; +use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, GenericParamDefKind}; use rustc::ty::subst::Subst; @@ -24,8 +24,6 @@ use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk}; use syntax_pos::Span; use rustc::hir; -use rustc_data_structures::accumulate_vec::AccumulateVec; -use rustc_data_structures::array_vec::ArrayVec; use std::ops::Deref; @@ -325,86 +323,41 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // parameters from the type and those from the method. assert_eq!(method_generics.parent_count, parent_substs.len()); - // Collect the segments of the path: we need to substitute arguments - // for parameters throughout the entire path (wherever there are - // generic parameters). - let def_id = pick.item.def_id; - let mut parent_defs = self.tcx.generics_of(def_id); - let count = parent_defs.count(); - let mut stack = vec![(def_id, parent_defs)]; - while let Some(def_id) = parent_defs.parent { - parent_defs = self.tcx.generics_of(def_id); - stack.push((def_id, parent_defs)); - } - - // We manually build up the substitution, rather than using convenience - // methods in subst.rs so that we can iterate over the arguments and - // parameters in lock-step linearly, rather than trying to match each pair. - let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 { - AccumulateVec::Array(ArrayVec::new()) - } else { - AccumulateVec::Heap(Vec::with_capacity(count)) - }; - fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) { - match substs { - AccumulateVec::Array(ref mut arr) => arr.push(kind), - AccumulateVec::Heap(ref mut vec) => vec.push(kind), - } - } - - // Iterate over each segment of the path. - while let Some((_, defs)) = stack.pop() { - let mut params = defs.params.iter(); - let mut next_param = params.next(); - - while let Some(param) = next_param { - if let Some(&kind) = parent_substs.get(param.index as usize) { - push_kind(&mut substs, kind); - next_param = params.next(); + AstConv::create_substs_for_generic_args( + self.tcx, + self.span, + false, + pick.item.def_id, + parent_substs, + false, + None, + // Provide the generic args, and whether types should be inferred. + |_| { + // The last argument of the returned tuple here is unimportant. + if let Some(ref data) = segment.args { + (Some(data), false) } else { - break; + (None, false) } - } - - if let Some(ref data) = segment.args { - let args = &data.args; - 'args: for arg in args { - while let Some(param) = next_param { - match param.kind { - GenericParamDefKind::Lifetime => match arg { - GenericArg::Lifetime(lt) => { - push_kind(&mut substs, AstConv::ast_region_to_region( - self.fcx, lt, Some(param)).into()); - next_param = params.next(); - continue 'args; - } - _ => { - push_kind(&mut substs, self.var_for_def(self.span, param)); - next_param = params.next(); - } - } - GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => { - push_kind(&mut substs, self.to_ty(ty).into()); - next_param = params.next(); - continue 'args; - } - _ => { - break 'args; - } - } + }, + // Provide substitutions for parameters for which (valid) arguments have been provided. + |param, arg| { + match param.kind { + GenericParamDefKind::Lifetime => match arg { + GenericArg::Lifetime(lt) => { + AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into() } + _ => unreachable!(), + } + GenericParamDefKind::Type { .. } => match arg { + GenericArg::Type(ty) => self.to_ty(ty).into(), + _ => unreachable!(), } } - } - - while let Some(param) = next_param { - push_kind(&mut substs, self.var_for_def(self.span, param)); - next_param = params.next(); - } - } - - self.tcx.intern_substs(&substs) + }, + // Provide substitutions for parameters for which arguments are inferred. + |_, param, _| self.var_for_def(self.span, param), + ) } fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1ef296774ea83..141d0aea4628e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,7 +95,7 @@ use rustc::infer::anon_types::AnonTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; use rustc::mir::interpret::{GlobalId}; -use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs}; +use rustc::ty::subst::{UnpackedKind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; @@ -103,8 +103,6 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::query::Providers; use rustc::ty::util::{Representability, IntTypeExt, Discr}; use errors::{DiagnosticBuilder, DiagnosticId}; -use rustc_data_structures::accumulate_vec::AccumulateVec; -use rustc_data_structures::array_vec::ArrayVec; use require_c_abi_if_variadic; use session::{CompileIncomplete, config, Session}; @@ -4282,8 +4280,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { match *qpath { hir::QPath::Resolved(ref maybe_qself, ref path) => { - let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); - let ty = AstConv::def_to_ty(self, opt_self_ty, path, true); + let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); + let ty = AstConv::def_to_ty(self, self_ty, path, true); (path.def, ty) } hir::QPath::TypeRelative(ref qself, ref segment) => { @@ -4873,7 +4871,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // number of type parameters and type. pub fn instantiate_value_path(&self, segments: &[hir::PathSegment], - opt_self_ty: Option>, + self_ty: Option>, def: Def, span: Span, node_id: ast::NodeId) @@ -4898,7 +4896,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if segments.len() == 1 { // `::assoc` will end up here, and so can `T::assoc`. - let self_ty = opt_self_ty.expect("UFCS sugared assoc missing Self"); + let self_ty = self_ty.expect("UFCS sugared assoc missing Self"); ufcs_associated = Some((container, self_ty)); } } @@ -4955,122 +4953,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.generics_of(*def_id).has_self }).unwrap_or(false); - // Collect the segments of the path: we need to substitute arguments - // for parameters throughout the entire path (wherever there are - // generic parameters). let def_id = def.def_id(); - let mut parent_defs = self.tcx.generics_of(def_id); - let count = parent_defs.count(); - let mut stack = vec![(def_id, parent_defs)]; - while let Some(def_id) = parent_defs.parent { - parent_defs = self.tcx.generics_of(def_id); - stack.push((def_id, parent_defs)); - } - // We manually build up the substitution, rather than using convenience - // methods in subst.rs so that we can iterate over the arguments and - // parameters in lock-step linearly, rather than trying to match each pair. - let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 { - AccumulateVec::Array(ArrayVec::new()) - } else { - AccumulateVec::Heap(Vec::with_capacity(count)) - }; - fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) { - match substs { - AccumulateVec::Array(ref mut arr) => arr.push(kind), - AccumulateVec::Heap(ref mut vec) => vec.push(kind), - } - } - - // Iterate over each segment of the path. - while let Some((def_id, defs)) = stack.pop() { - let mut params = defs.params.iter(); - let mut next_param = params.next(); - - // `Self` is handled first. - if has_self { - if let Some(param) = next_param { - if param.index == 0 { - if let GenericParamDefKind::Type { .. } = param.kind { - push_kind(&mut substs, opt_self_ty.map(|ty| ty.into()) - .unwrap_or_else(|| self.var_for_def(span, param))); - next_param = params.next(); + let substs = AstConv::create_substs_for_generic_args( + self.tcx, + span, + true, + def_id, + &[][..], + has_self, + self_ty, + // Provide the generic args, and whether types should be inferred. + |def_id| { + if let Some(&PathSeg(_, index)) = path_segs.iter().find(|&PathSeg(did, _)| { + *did == def_id + }) { + // If we've encountered an `impl Trait`-related error, we're just + // going to infer the arguments for better error messages. + if !supress_errors[&index] { + // Check whether the user has provided generic arguments. + if let Some(ref data) = segments[index].args { + return (Some(data), segments[index].infer_types); } } + return (None, segments[index].infer_types); } - } - let mut infer_types = true; - // Check whether this segment takes generic arguments. - if let Some(&PathSeg(_, index)) = path_segs - .iter() - .find(|&PathSeg(did, _)| *did == def_id) { - // If we've encountered an `impl Trait`-related error, we're just - // going to infer the arguments for better error messages. - if !supress_errors[&index] { - infer_types = segments[index].infer_types; - // Check whether the user has provided generic arguments. - if let Some(ref data) = segments[index].args { - let args = &data.args; - // We're going to iterate through the generic arguments that the user - // provided, matching them with the generic parameters we expect. - // Mismatches can occur as a result of elided lifetimes, or for malformed - // input. We try to handle both sensibly. - 'args: for arg in args { - while let Some(param) = next_param { - match param.kind { - GenericParamDefKind::Lifetime => match arg { - GenericArg::Lifetime(lt) => { - push_kind(&mut substs, - AstConv::ast_region_to_region(self, lt, Some(param)) - .into()); - next_param = params.next(); - continue 'args; - } - GenericArg::Type(_) => { - // We expected a lifetime argument, but got a type - // argument. That means we're inferring the lifetimes. - push_kind(&mut substs, - self.re_infer(span, Some(param)).unwrap().into()); - next_param = params.next(); - } - } - GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => { - push_kind(&mut substs, self.to_ty(ty).into()); - next_param = params.next(); - continue 'args; - } - GenericArg::Lifetime(_) => { - // We expected a type argument, but got a lifetime - // argument. This is an error, but we need to handle it - // gracefully so we can report sensible errors. In this - // case, we're simply going to infer the remaining - // arguments. - self.tcx.sess.delay_span_bug(span, - "found a GenericArg::Lifetime where a \ - GenericArg::Type was expected"); - break 'args; - } - } - } - } - // We should never be able to reach this point with well-formed input. - // Getting to this point means the user supplied more arguments than - // there are parameters. - self.tcx.sess.delay_span_bug(span, - "GenericArg did not have matching GenericParamDef"); + (None, true) + }, + // Provide substitutions for parameters for which (valid) arguments have been provided. + |param, arg| { + match param.kind { + GenericParamDefKind::Lifetime => match arg { + GenericArg::Lifetime(lt) => { + AstConv::ast_region_to_region(self, lt, Some(param)).into() } + _ => unreachable!(), + } + GenericParamDefKind::Type { .. } => match arg { + GenericArg::Type(ty) => self.to_ty(ty).into(), + _ => unreachable!(), } } - } - - // If there are fewer arguments than parameters, it means - // we're inferring the remaining arguments. - while let Some(param) = next_param { + }, + // Provide substitutions for parameters for which arguments are inferred. + |substs, param, infer_types| { match param.kind { GenericParamDefKind::Lifetime => { - push_kind(&mut substs, self.re_infer(span, Some(param)).unwrap().into()); + self.re_infer(span, Some(param)).unwrap().into() } GenericParamDefKind::Type { has_default, .. } => { if !infer_types && has_default { @@ -5078,24 +5008,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // inferring the type arguments: we provide the default where any // is missing. let default = self.tcx.type_of(param.def_id); - let kind = self.normalize_ty( + self.normalize_ty( span, - default.subst_spanned(self.tcx, &substs, Some(span)) - ).into(); - push_kind(&mut substs, kind); + default.subst_spanned(self.tcx, substs.unwrap(), Some(span)) + ).into() } else { // If no type arguments were provided, we have to infer them. // This case also occurs as a result of some malformed input, e.g. // a lifetime argument being given instead of a type paramter. // Using inference instead of `TyError` gives better error messages. - push_kind(&mut substs, self.var_for_def(span, param)); + self.var_for_def(span, param) } } } - next_param = params.next(); - } - } - let substs = self.tcx.intern_substs(&substs); + }, + ); // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. From 6a96cf12c1583978a1e07bcd26db152cb459e03c Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 2 Aug 2018 18:09:14 +0100 Subject: [PATCH 28/41] Clean match statement --- src/librustc_typeck/astconv.rs | 58 ++++++++++++++++------------------ 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 83c18265489f3..6b8844a7de389 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -274,39 +274,35 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // input. We try to handle both sensibly. 'args: for arg in &generic_args.args { while let Some(param) = next_param { - match param.kind { - GenericParamDefKind::Lifetime => match arg { - GenericArg::Lifetime(_) => { - push_kind(&mut substs, provided_kind(param, arg)); - next_param = params.next(); - continue 'args; - } - GenericArg::Type(_) => { - // We expected a lifetime argument, but got a type - // argument. That means we're inferring the lifetimes. - push_kind(&mut substs, inferred_kind(None, param, infer_types)); - next_param = params.next(); - } + match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(_)) => { + push_kind(&mut substs, provided_kind(param, arg)); + next_param = params.next(); + continue 'args; } - GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(_) => { - push_kind(&mut substs, provided_kind(param, arg)); - next_param = params.next(); - continue 'args; - } - GenericArg::Lifetime(_) => { - // We expected a type argument, but got a lifetime - // argument. This is an error, but we need to handle it - // gracefully so we can report sensible errors. In this - // case, we're simply going to infer the remaining - // arguments. - if err_if_invalid { - tcx.sess.delay_span_bug(span, - "found a GenericArg::Lifetime where a \ - GenericArg::Type was expected"); - } - break 'args; + (GenericParamDefKind::Lifetime, GenericArg::Type(_)) => { + // We expected a lifetime argument, but got a type + // argument. That means we're inferring the lifetimes. + push_kind(&mut substs, inferred_kind(None, param, infer_types)); + next_param = params.next(); + } + (GenericParamDefKind::Type { .. }, GenericArg::Type(_)) => { + push_kind(&mut substs, provided_kind(param, arg)); + next_param = params.next(); + continue 'args; + } + (GenericParamDefKind::Type { .. }, GenericArg::Lifetime(_)) => { + // We expected a type argument, but got a lifetime + // argument. This is an error, but we need to handle it + // gracefully so we can report sensible errors. In this + // case, we're simply going to infer the remaining + // arguments. + if err_if_invalid { + tcx.sess.delay_span_bug(span, + "found a GenericArg::Lifetime where a \ + GenericArg::Type was expected"); } + break 'args; } } } From 9d3d4b1a19f57c57caa1803bc05b5619eb0df964 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 7 Aug 2018 12:28:08 +0100 Subject: [PATCH 29/41] Refactor lock-step --- src/librustc_typeck/astconv.rs | 66 ++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6b8844a7de389..a95f4c6c941cf 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -267,29 +267,33 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // Check whether this segment takes generic arguments and the user has provided any. let (generic_args, infer_types) = args_for_def_id(def_id); - if let Some(ref generic_args) = generic_args { + + let mut args = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()); + let mut next_arg = args.next(); + + loop { // We're going to iterate through the generic arguments that the user // provided, matching them with the generic parameters we expect. // Mismatches can occur as a result of elided lifetimes, or for malformed // input. We try to handle both sensibly. - 'args: for arg in &generic_args.args { - while let Some(param) = next_param { + let mut progress_arg = true; + match (next_arg, next_param) { + (Some(arg), Some(param)) => { match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(_)) => { push_kind(&mut substs, provided_kind(param, arg)); next_param = params.next(); - continue 'args; } (GenericParamDefKind::Lifetime, GenericArg::Type(_)) => { // We expected a lifetime argument, but got a type // argument. That means we're inferring the lifetimes. push_kind(&mut substs, inferred_kind(None, param, infer_types)); next_param = params.next(); + progress_arg = false; } (GenericParamDefKind::Type { .. }, GenericArg::Type(_)) => { push_kind(&mut substs, provided_kind(param, arg)); next_param = params.next(); - continue 'args; } (GenericParamDefKind::Type { .. }, GenericArg::Lifetime(_)) => { // We expected a type argument, but got a lifetime @@ -300,35 +304,43 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { if err_if_invalid { tcx.sess.delay_span_bug(span, "found a GenericArg::Lifetime where a \ - GenericArg::Type was expected"); + GenericArg::Type was expected"); + } + // Exhaust the iterator. + while next_arg.is_some() { + next_arg = args.next(); } - break 'args; } } } - // We should never be able to reach this point with well-formed input. - // Getting to this point means the user supplied more arguments than - // there are parameters. - if err_if_invalid { - tcx.sess.delay_span_bug(span, - "GenericArg did not have matching GenericParamDef"); - } - } - } - - // If there are fewer arguments than parameters, it means - // we're inferring the remaining arguments. - while let Some(param) = next_param { - match param.kind { - GenericParamDefKind::Lifetime => { - push_kind(&mut substs, inferred_kind(None, param, infer_types)); + (Some(_), None) => { + // We should never be able to reach this point with well-formed input. + // Getting to this point means the user supplied more arguments than + // there are parameters. + if err_if_invalid { + tcx.sess.delay_span_bug(span, + "GenericArg did not have matching GenericParamDef"); + } } - GenericParamDefKind::Type { .. } => { - let kind = inferred_kind(Some(&substs), param, infer_types); - push_kind(&mut substs, kind); + (None, Some(param)) => { + // If there are fewer arguments than parameters, it means + // we're inferring the remaining arguments. + match param.kind { + GenericParamDefKind::Lifetime => { + push_kind(&mut substs, inferred_kind(None, param, infer_types)); + } + GenericParamDefKind::Type { .. } => { + let kind = inferred_kind(Some(&substs), param, infer_types); + push_kind(&mut substs, kind); + } + } + next_param = params.next(); } + (None, None) => break, + } + if progress_arg { + next_arg = args.next(); } - next_param = params.next(); } } From 7c9f7c2fa3b48f8bfefa148dc425db68684cf953 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 7 Aug 2018 17:01:12 +0100 Subject: [PATCH 30/41] Args first, then params --- src/librustc_typeck/astconv.rs | 46 +++++++-------------- src/librustc_typeck/check/method/confirm.rs | 2 - src/librustc_typeck/check/mod.rs | 2 - 3 files changed, 15 insertions(+), 35 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a95f4c6c941cf..30f1ed1317ddb 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -196,8 +196,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { /// corresponding to a set of generic parameters. pub fn create_substs_for_generic_args<'a, 'b, A, P, I>( tcx: TyCtxt<'a, 'gcx, 'tcx>, - span: Span, - err_if_invalid: bool, def_id: DefId, parent_substs: &[Kind<'tcx>], has_self: bool, @@ -279,37 +277,29 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { let mut progress_arg = true; match (next_arg, next_param) { (Some(arg), Some(param)) => { - match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(_)) => { + match (arg, ¶m.kind) { + (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime) => { push_kind(&mut substs, provided_kind(param, arg)); next_param = params.next(); } - (GenericParamDefKind::Lifetime, GenericArg::Type(_)) => { - // We expected a lifetime argument, but got a type - // argument. That means we're inferring the lifetimes. - push_kind(&mut substs, inferred_kind(None, param, infer_types)); - next_param = params.next(); - progress_arg = false; - } - (GenericParamDefKind::Type { .. }, GenericArg::Type(_)) => { - push_kind(&mut substs, provided_kind(param, arg)); - next_param = params.next(); - } - (GenericParamDefKind::Type { .. }, GenericArg::Lifetime(_)) => { + (GenericArg::Lifetime(_), GenericParamDefKind::Type { .. }) => { // We expected a type argument, but got a lifetime // argument. This is an error, but we need to handle it // gracefully so we can report sensible errors. In this // case, we're simply going to infer the remaining // arguments. - if err_if_invalid { - tcx.sess.delay_span_bug(span, - "found a GenericArg::Lifetime where a \ - GenericArg::Type was expected"); - } - // Exhaust the iterator. - while next_arg.is_some() { - next_arg = args.next(); - } + args.by_ref().for_each(drop); // Exhaust the iterator. + } + (GenericArg::Type(_), GenericParamDefKind::Type { .. }) => { + push_kind(&mut substs, provided_kind(param, arg)); + next_param = params.next(); + } + (GenericArg::Type(_), GenericParamDefKind::Lifetime) => { + // We expected a lifetime argument, but got a type + // argument. That means we're inferring the lifetimes. + push_kind(&mut substs, inferred_kind(None, param, infer_types)); + next_param = params.next(); + progress_arg = false; } } } @@ -317,10 +307,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // We should never be able to reach this point with well-formed input. // Getting to this point means the user supplied more arguments than // there are parameters. - if err_if_invalid { - tcx.sess.delay_span_bug(span, - "GenericArg did not have matching GenericParamDef"); - } } (None, Some(param)) => { // If there are fewer arguments than parameters, it means @@ -428,8 +414,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { let substs = Self::create_substs_for_generic_args( self.tcx(), - span, - false, def_id, &[][..], self_ty.is_some(), diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 0acbd8031035d..739c2013950c8 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -325,8 +325,6 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { AstConv::create_substs_for_generic_args( self.tcx, - self.span, - false, pick.item.def_id, parent_substs, false, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 141d0aea4628e..f37ea81912231 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4957,8 +4957,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let substs = AstConv::create_substs_for_generic_args( self.tcx, - span, - true, def_id, &[][..], has_self, From a14bc713e77cfdf2c91e2e24f428f9dd13da786a Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 7 Aug 2018 17:44:30 +0100 Subject: [PATCH 31/41] Add Default for GenericParamCount --- src/librustc/hir/mod.rs | 22 ++++++++++++++++++---- src/librustc/ty/mod.rs | 6 ++---- src/librustc/util/ppaux.rs | 5 +---- src/librustdoc/clean/mod.rs | 5 +---- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 589f3c9d87cf5..991b80ad3e916 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -445,6 +445,22 @@ impl GenericArgs { } bug!("GenericArgs::inputs: not a `Fn(T) -> U`"); } + + pub fn own_counts(&self) -> GenericParamCount { + // We could cache this as a property of `GenericParamCount`, but + // the aim is to refactor this away entirely eventually and the + // presence of this method will be a constant reminder. + let mut own_counts: GenericParamCount = Default::default(); + + for arg in &self.args { + match arg { + GenericArg::Lifetime(_) => own_counts.lifetimes += 1, + GenericArg::Type(_) => own_counts.types += 1, + }; + } + + own_counts + } } /// A modifier on a bound, currently this is only used for `?Sized`, where the @@ -503,6 +519,7 @@ pub struct GenericParam { pub kind: GenericParamKind, } +#[derive(Default)] pub struct GenericParamCount { pub lifetimes: usize, pub types: usize, @@ -533,10 +550,7 @@ impl Generics { // We could cache this as a property of `GenericParamCount`, but // the aim is to refactor this away entirely eventually and the // presence of this method will be a constant reminder. - let mut own_counts = GenericParamCount { - lifetimes: 0, - types: 0, - }; + let mut own_counts: GenericParamCount = Default::default(); for param in &self.params { match param.kind { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4479c7239df50..3e4527cacd4e1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -881,6 +881,7 @@ impl GenericParamDef { } } +#[derive(Default)] pub struct GenericParamCount { pub lifetimes: usize, pub types: usize, @@ -913,10 +914,7 @@ impl<'a, 'gcx, 'tcx> Generics { // We could cache this as a property of `GenericParamCount`, but // the aim is to refactor this away entirely eventually and the // presence of this method will be a constant reminder. - let mut own_counts = GenericParamCount { - lifetimes: 0, - types: 0, - }; + let mut own_counts: GenericParamCount = Default::default(); for param in &self.params { match param.kind { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index bb54e18360495..9513086667b28 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -262,10 +262,7 @@ impl PrintContext { let verbose = self.is_verbose; let mut num_supplied_defaults = 0; let mut has_self = false; - let mut own_counts = GenericParamCount { - lifetimes: 0, - types: 0, - }; + let mut own_counts: GenericParamCount = Default::default(); let mut is_value_path = false; let fn_trait_kind = ty::tls::with(|tcx| { // Unfortunately, some kinds of items (e.g., closures) don't have diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ad774f9860264..687a606cecb69 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2432,10 +2432,7 @@ impl Clean for hir::Ty { let mut ty_substs = FxHashMap(); let mut lt_substs = FxHashMap(); provided_params.with_generic_args(|generic_args| { - let mut indices = ty::GenericParamCount { - lifetimes: 0, - types: 0 - }; + let mut indices: GenericParamCount = Default::default(); for param in generics.params.iter() { match param.kind { hir::GenericParamKind::Lifetime { .. } => { From 49c45734c0d1a038e44767bdf9cd6721652d5002 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 7 Aug 2018 18:53:43 +0100 Subject: [PATCH 32/41] Refactor generic argument count check in astconv --- src/librustc/ty/mod.rs | 2 +- src/librustc_typeck/astconv.rs | 215 +++++++++--------- src/test/ui/bad/bad-mid-path-type-params.rs | 2 +- src/test/ui/error-codes/E0107.rs | 6 +- src/test/ui/error-codes/E0107.stderr | 12 +- src/test/ui/error-codes/E0244.stderr | 2 +- ...eric-type-more-params-with-defaults.stderr | 2 +- src/test/ui/issues/issue-18423.rs | 4 +- src/test/ui/issues/issue-18423.stderr | 6 +- src/test/ui/issues/issue-3214.stderr | 2 +- .../ui/traits/trait-object-vs-lifetime.rs | 2 +- .../typeck-builtin-bound-type-parameters.rs | 4 +- ...ypeck-builtin-bound-type-parameters.stderr | 16 +- .../typeck_type_placeholder_lifetime_1.stderr | 2 +- .../typeck_type_placeholder_lifetime_2.stderr | 2 +- .../unboxed-closure-sugar-region.rs | 2 +- .../unboxed-closure-sugar-wrong-trait.stderr | 2 +- 17 files changed, 140 insertions(+), 143 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3e4527cacd4e1..f6d21ca5861fb 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -919,7 +919,7 @@ impl<'a, 'gcx, 'tcx> Generics { for param in &self.params { match param.kind { GenericParamDefKind::Lifetime => own_counts.lifetimes += 1, - GenericParamDefKind::Type {..} => own_counts.types += 1, + GenericParamDefKind::Type { .. } => own_counts.types += 1, }; } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 30f1ed1317ddb..cd297d5c653af 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -29,7 +29,7 @@ use std::slice; use require_c_abi_if_variadic; use util::common::ErrorReported; use util::nodemap::{FxHashSet, FxHashMap}; -use errors::FatalError; +use errors::{FatalError, DiagnosticId}; use std::iter; use syntax::ast; @@ -89,11 +89,6 @@ struct ConvertedBinding<'tcx> { span: Span, } -struct ParamRange { - required: usize, - accepted: usize -} - /// Dummy type used for the `Self` of a `TraitRef` created for converting /// a trait object, and which gets removed in `ExistentialTraitRef`. /// This type must not appear anywhere in other converted types. @@ -346,56 +341,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { self_ty: Option>) -> (&'tcx Substs<'tcx>, Vec>) { - let tcx = self.tcx(); - - debug!("create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \ - generic_args={:?})", - def_id, self_ty, generic_args); - // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). - let mut lt_provided = 0; - let mut ty_provided = 0; - for arg in &generic_args.args { - match arg { - GenericArg::Lifetime(_) => lt_provided += 1, - GenericArg::Type(_) => ty_provided += 1, - } - } - - let decl_generics = tcx.generics_of(def_id); - let mut lt_accepted = 0; - let mut ty_params = ParamRange { required: 0, accepted: 0 }; - for param in &decl_generics.params { - match param.kind { - GenericParamDefKind::Lifetime => { - lt_accepted += 1; - } - GenericParamDefKind::Type { has_default, .. } => { - ty_params.accepted += 1; - if !has_default { - ty_params.required += 1; - } - } - }; - } - if self_ty.is_some() { - ty_params.required -= 1; - ty_params.accepted -= 1; - } + debug!("create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \ + generic_args={:?})", + def_id, self_ty, generic_args); - if lt_accepted != lt_provided { - report_lifetime_number_error(tcx, span, lt_provided, lt_accepted); - } + let tcx = self.tcx(); + let generic_params = tcx.generics_of(def_id); // If a self-type was declared, one should be provided. - assert_eq!(decl_generics.has_self, self_ty.is_some()); + assert_eq!(generic_params.has_self, self_ty.is_some()); - // Check the number of type parameters supplied by the user. - if !infer_types || ty_provided > ty_params.required { - check_type_argument_count(tcx, span, ty_provided, ty_params); - } + let has_self = generic_params.has_self; + check_generic_arg_count(tcx, span, &generic_params, &generic_args, has_self, infer_types); let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); let default_needs_object_self = |param: &ty::GenericParamDef| { @@ -492,8 +452,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } }).collect(); - debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", - decl_generics, self_ty, substs); + debug!("create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", + generic_params, self_ty, substs); (substs, assoc_bindings) } @@ -1537,70 +1497,107 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, (auto_traits, trait_bounds) } -fn check_type_argument_count(tcx: TyCtxt, - span: Span, - supplied: usize, - ty_params: ParamRange) -{ - let (required, accepted) = (ty_params.required, ty_params.accepted); - if supplied < required { - let expected = if required < accepted { - "expected at least" - } else { - "expected" - }; - let arguments_plural = if required == 1 { "" } else { "s" }; - - struct_span_err!(tcx.sess, span, E0243, - "wrong number of type arguments: {} {}, found {}", - expected, required, supplied) - .span_label(span, - format!("{} {} type argument{}", - expected, - required, - arguments_plural)) - .emit(); - } else if supplied > accepted { - let expected = if required < accepted { - format!("expected at most {}", accepted) - } else { - format!("expected {}", accepted) +pub fn check_generic_arg_count( + tcx: TyCtxt, + span: Span, + def: &ty::Generics, + args: &hir::GenericArgs, + has_self: bool, + infer_types: bool, +) { + // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. + // that lifetimes will proceed types. So it suffices to check the number of each generic + // arguments in order to validate them with respect to the generic parameters. + let param_counts = def.own_counts(); + let arg_counts = args.own_counts(); + + let mut defaults: ty::GenericParamCount = Default::default(); + for param in &def.params { + match param.kind { + GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Type { has_default, .. } => defaults.types += has_default as usize, }; - let arguments_plural = if accepted == 1 { "" } else { "s" }; - - struct_span_err!(tcx.sess, span, E0244, - "wrong number of type arguments: {}, found {}", - expected, supplied) - .span_label( - span, - format!("{} type argument{}", - if accepted == 0 { "expected no" } else { &expected }, - arguments_plural) - ) - .emit(); } -} -fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected: usize) { - let label = if number < expected { - if expected == 1 { - format!("expected {} lifetime parameter", expected) - } else { - format!("expected {} lifetime parameters", expected) + let check_kind_count = |error_code_less: &str, + error_code_more: &str, + kind, + required, + permitted, + provided| { + // We enforce the following: `required` <= `provided` <= `permitted`. + // For kinds without defaults (i.e. lifetimes), `required == permitted`. + // For other kinds (i.e. types), `permitted` may be greater than `required`. + if required <= provided && provided <= permitted { + return; } - } else { - let additional = number - expected; - if additional == 1 { - "unexpected lifetime parameter".to_string() + + // Unfortunately lifetime and type parameter mismatches are typically styled + // differently in diagnostics, which means we have a few cases to consider here. + let (bound, quantifier) = if required != permitted { + if provided < required { + (required, "at least ") + } else { // provided > permitted + (permitted, "at most ") + } } else { - format!("{} unexpected lifetime parameters", additional) - } + (required, "") + }; + let label = if required == permitted && provided > permitted { + let diff = provided - permitted; + format!( + "{}unexpected {} argument{}", + if diff != 1 { format!("{} ", diff) } else { String::new() }, + kind, + if diff != 1 { "s" } else { "" }, + ) + } else { + format!( + "expected {}{} {} argument{}", + quantifier, + bound, + kind, + if required != 1 { "s" } else { "" }, + ) + }; + + tcx.sess.struct_span_err_with_code( + span, + &format!( + "wrong number of {} arguments: expected {}{}, found {}", + kind, + quantifier, + bound, + provided, + ), + DiagnosticId::Error({ + if provided <= permitted { + error_code_less + } else { + error_code_more + } + }.into()) + ).span_label(span, label).emit(); }; - struct_span_err!(tcx.sess, span, E0107, - "wrong number of lifetime parameters: expected {}, found {}", - expected, number) - .span_label(span, label) - .emit(); + + check_kind_count( + "E0107", + "E0107", + "lifetime", + param_counts.lifetimes, + param_counts.lifetimes, + arg_counts.lifetimes, + ); + if !infer_types || arg_counts.types > param_counts.types - defaults.types - has_self as usize { + check_kind_count( + "E0243", + "E0244", // FIXME: E0243 and E0244 should be unified. + "type", + param_counts.types - defaults.types - has_self as usize, + param_counts.types - has_self as usize, + arg_counts.types, + ); + } } // A helper struct for conveniently grouping a set of bounds which we pass to diff --git a/src/test/ui/bad/bad-mid-path-type-params.rs b/src/test/ui/bad/bad-mid-path-type-params.rs index 20ac757354faf..4645142ea66fa 100644 --- a/src/test/ui/bad/bad-mid-path-type-params.rs +++ b/src/test/ui/bad/bad-mid-path-type-params.rs @@ -41,7 +41,7 @@ fn foo<'a>() { //~^ ERROR too many type parameters provided let _ = S::<'a,isize>::new::(1, 1.0); - //~^ ERROR wrong number of lifetime parameters + //~^ ERROR wrong number of lifetime arguments let _: S2 = Trait::new::(1, 1.0); //~^ ERROR too many type parameters provided diff --git a/src/test/ui/error-codes/E0107.rs b/src/test/ui/error-codes/E0107.rs index 3b0eedae14c1d..815c7fefd2a96 100644 --- a/src/test/ui/error-codes/E0107.rs +++ b/src/test/ui/error-codes/E0107.rs @@ -20,13 +20,13 @@ enum Bar { struct Baz<'a, 'b, 'c> { buzz: Buzz<'a>, //~^ ERROR E0107 - //~| expected 2 lifetime parameters + //~| expected 2 lifetime arguments bar: Bar<'a>, //~^ ERROR E0107 - //~| unexpected lifetime parameter + //~| unexpected lifetime argument foo2: Foo<'a, 'b, 'c>, //~^ ERROR E0107 - //~| 2 unexpected lifetime parameters + //~| 2 unexpected lifetime arguments } fn main() {} diff --git a/src/test/ui/error-codes/E0107.stderr b/src/test/ui/error-codes/E0107.stderr index 76bb2667643e6..07f4f322695c3 100644 --- a/src/test/ui/error-codes/E0107.stderr +++ b/src/test/ui/error-codes/E0107.stderr @@ -1,20 +1,20 @@ -error[E0107]: wrong number of lifetime parameters: expected 2, found 1 +error[E0107]: wrong number of lifetime arguments: expected 2, found 1 --> $DIR/E0107.rs:21:11 | LL | buzz: Buzz<'a>, - | ^^^^^^^^ expected 2 lifetime parameters + | ^^^^^^^^ expected 2 lifetime arguments -error[E0107]: wrong number of lifetime parameters: expected 0, found 1 +error[E0107]: wrong number of lifetime arguments: expected 0, found 1 --> $DIR/E0107.rs:24:10 | LL | bar: Bar<'a>, - | ^^^^^^^ unexpected lifetime parameter + | ^^^^^^^ unexpected lifetime argument -error[E0107]: wrong number of lifetime parameters: expected 1, found 3 +error[E0107]: wrong number of lifetime arguments: expected 1, found 3 --> $DIR/E0107.rs:27:11 | LL | foo2: Foo<'a, 'b, 'c>, - | ^^^^^^^^^^^^^^^ 2 unexpected lifetime parameters + | ^^^^^^^^^^^^^^^ 2 unexpected lifetime arguments error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0244.stderr b/src/test/ui/error-codes/E0244.stderr index e323970396255..87f063c604fe4 100644 --- a/src/test/ui/error-codes/E0244.stderr +++ b/src/test/ui/error-codes/E0244.stderr @@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 2 --> $DIR/E0244.rs:12:23 | LL | struct Bar { x: Foo } - | ^^^^^^^^^ expected no type arguments + | ^^^^^^^^^ 2 unexpected type arguments error: aborting due to previous error diff --git a/src/test/ui/generic/generic-type-more-params-with-defaults.stderr b/src/test/ui/generic/generic-type-more-params-with-defaults.stderr index 684a22ce45c92..f226921816d09 100644 --- a/src/test/ui/generic/generic-type-more-params-with-defaults.stderr +++ b/src/test/ui/generic/generic-type-more-params-with-defaults.stderr @@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected at most 2, found 3 --> $DIR/generic-type-more-params-with-defaults.rs:19:12 | LL | let _: Vec; - | ^^^^^^^^^^^^^^^^^^^^^^ expected at most 2 type arguments + | ^^^^^^^^^^^^^^^^^^^^^^ expected at most 2 type argument error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18423.rs b/src/test/ui/issues/issue-18423.rs index 5945a7a1c9a7e..f550dc6f310ff 100644 --- a/src/test/ui/issues/issue-18423.rs +++ b/src/test/ui/issues/issue-18423.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that `Box` cannot be used with a lifetime parameter. +// Test that `Box` cannot be used with a lifetime argument. struct Foo<'a> { - x: Box<'a, isize> //~ ERROR wrong number of lifetime parameters + x: Box<'a, isize> //~ ERROR wrong number of lifetime arguments } pub fn main() { diff --git a/src/test/ui/issues/issue-18423.stderr b/src/test/ui/issues/issue-18423.stderr index 25406198193a4..35063f3d3ad06 100644 --- a/src/test/ui/issues/issue-18423.stderr +++ b/src/test/ui/issues/issue-18423.stderr @@ -1,8 +1,8 @@ -error[E0107]: wrong number of lifetime parameters: expected 0, found 1 +error[E0107]: wrong number of lifetime arguments: expected 0, found 1 --> $DIR/issue-18423.rs:14:8 | -LL | x: Box<'a, isize> //~ ERROR wrong number of lifetime parameters - | ^^^^^^^^^^^^^^ unexpected lifetime parameter +LL | x: Box<'a, isize> //~ ERROR wrong number of lifetime arguments + | ^^^^^^^^^^^^^^ unexpected lifetime argument error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3214.stderr b/src/test/ui/issues/issue-3214.stderr index 1298e4a007d41..d1b846eb2aa8e 100644 --- a/src/test/ui/issues/issue-3214.stderr +++ b/src/test/ui/issues/issue-3214.stderr @@ -13,7 +13,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/issue-3214.rs:16:22 | LL | impl Drop for foo { - | ^^^^^^ expected no type arguments + | ^^^^^^ unexpected type argument error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-object-vs-lifetime.rs b/src/test/ui/traits/trait-object-vs-lifetime.rs index a70141edc29f2..954e20e334566 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.rs +++ b/src/test/ui/traits/trait-object-vs-lifetime.rs @@ -21,7 +21,7 @@ fn main() { let _: S<'static, 'static +>; //~^ at least one non-builtin trait is required for an object type let _: S<'static, 'static>; - //~^ ERROR wrong number of lifetime parameters: expected 1, found 2 + //~^ ERROR wrong number of lifetime arguments: expected 1, found 2 //~| ERROR wrong number of type arguments: expected 1, found 0 let _: S<'static +, 'static>; //~^ ERROR lifetime parameters must be declared prior to type parameters diff --git a/src/test/ui/typeck/typeck-builtin-bound-type-parameters.rs b/src/test/ui/typeck/typeck-builtin-bound-type-parameters.rs index 15fc3ecab97cb..9285b8ca6bcf0 100644 --- a/src/test/ui/typeck/typeck-builtin-bound-type-parameters.rs +++ b/src/test/ui/typeck/typeck-builtin-bound-type-parameters.rs @@ -18,12 +18,12 @@ struct MyStruct1>; //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] struct MyStruct2<'a, T: Copy<'a>>; -//~^ ERROR: wrong number of lifetime parameters: expected 0, found 1 +//~^ ERROR: wrong number of lifetime arguments: expected 0, found 1 fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] -//~| ERROR: wrong number of lifetime parameters: expected 0, found 1 +//~| ERROR: wrong number of lifetime arguments: expected 0, found 1 fn main() { } diff --git a/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr b/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr index 221f05b915090..d34818826295f 100644 --- a/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr +++ b/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr @@ -2,37 +2,37 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/typeck-builtin-bound-type-parameters.rs:11:11 | LL | fn foo1, U>(x: T) {} - | ^^^^^^^ expected no type arguments + | ^^^^^^^ unexpected type argument error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/typeck-builtin-bound-type-parameters.rs:14:14 | LL | trait Trait: Copy {} - | ^^^^^^^^^^ expected no type arguments + | ^^^^^^^^^^ unexpected type argument error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/typeck-builtin-bound-type-parameters.rs:17:21 | LL | struct MyStruct1>; - | ^^^^^^^ expected no type arguments + | ^^^^^^^ unexpected type argument -error[E0107]: wrong number of lifetime parameters: expected 0, found 1 +error[E0107]: wrong number of lifetime arguments: expected 0, found 1 --> $DIR/typeck-builtin-bound-type-parameters.rs:20:25 | LL | struct MyStruct2<'a, T: Copy<'a>>; - | ^^^^^^^^ unexpected lifetime parameter + | ^^^^^^^^ unexpected lifetime argument -error[E0107]: wrong number of lifetime parameters: expected 0, found 1 +error[E0107]: wrong number of lifetime arguments: expected 0, found 1 --> $DIR/typeck-builtin-bound-type-parameters.rs:24:15 | LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} - | ^^^^^^^^^^^ unexpected lifetime parameter + | ^^^^^^^^^^^ unexpected lifetime argument error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/typeck-builtin-bound-type-parameters.rs:24:15 | LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} - | ^^^^^^^^^^^ expected no type arguments + | ^^^^^^^^^^^ unexpected type argument error: aborting due to 6 previous errors diff --git a/src/test/ui/typeck/typeck_type_placeholder_lifetime_1.stderr b/src/test/ui/typeck/typeck_type_placeholder_lifetime_1.stderr index fe9566b318156..597fbc6d8b1bc 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_lifetime_1.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_lifetime_1.stderr @@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 1, found 2 --> $DIR/typeck_type_placeholder_lifetime_1.rs:19:12 | LL | let c: Foo<_, _> = Foo { r: &5 }; - | ^^^^^^^^^ expected 1 type argument + | ^^^^^^^^^ unexpected type argument error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck_type_placeholder_lifetime_2.stderr b/src/test/ui/typeck/typeck_type_placeholder_lifetime_2.stderr index 64ec424546666..1b7c60441e16b 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_lifetime_2.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_lifetime_2.stderr @@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 1, found 2 --> $DIR/typeck_type_placeholder_lifetime_2.rs:19:12 | LL | let c: Foo<_, usize> = Foo { r: &5 }; - | ^^^^^^^^^^^^^ expected 1 type argument + | ^^^^^^^^^^^^^ unexpected type argument error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.rs index 18a1185d695f7..331ad620c27c0 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.rs @@ -38,7 +38,7 @@ fn test<'a,'b>() { } fn test2(x: &Foo<(isize,),Output=()>, y: &Foo(isize)) { -//~^ ERROR wrong number of lifetime parameters: expected 1, found 0 +//~^ ERROR wrong number of lifetime arguments: expected 1, found 0 // Here, the omitted lifetimes are expanded to distinct things. same_type(x, y) } diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr index 82ba4e66393de..a993928bc318a 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr @@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:8 | LL | fn f isize>(x: F) {} - | ^^^^^^^^^^^^^^^^^^^^^ expected no type arguments + | ^^^^^^^^^^^^^^^^^^^^^ unexpected type argument error[E0220]: associated type `Output` not found for `Trait` --> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:24 From 68b0e7dd99ff374adf1babc481e415bad133cba7 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 8 Aug 2018 00:01:47 +0100 Subject: [PATCH 33/41] Refactor generic argument count check in method/confirm.rs --- src/librustc/hir/mod.rs | 7 + src/librustc_typeck/astconv.rs | 288 ++++++++++++-------- src/librustc_typeck/check/method/confirm.rs | 22 +- src/librustc_typeck/check/mod.rs | 2 +- 4 files changed, 195 insertions(+), 124 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 991b80ad3e916..8fb2bb63760a6 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -401,6 +401,13 @@ impl GenericArg { GenericArg::Type(t) => t.span, } } + + pub fn id(&self) -> NodeId { + match self { + GenericArg::Lifetime(l) => l.id, + GenericArg::Type(t) => t.id, + } + } } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index cd297d5c653af..2e59c5959fbe5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -30,11 +30,12 @@ use require_c_abi_if_variadic; use util::common::ErrorReported; use util::nodemap::{FxHashSet, FxHashMap}; use errors::{FatalError, DiagnosticId}; +use lint; use std::iter; use syntax::ast; use syntax::feature_gate::{GateIssue, emit_feature_err}; -use syntax_pos::Span; +use syntax_pos::{Span, MultiSpan}; pub trait AstConv<'gcx, 'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>; @@ -172,21 +173,164 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { -> &'tcx Substs<'tcx> { - let (substs, assoc_bindings) = - item_segment.with_generic_args(|generic_args| { - self.create_substs_for_ast_path( - span, - def_id, - generic_args, - item_segment.infer_types, - None) - }); + let (substs, assoc_bindings) = item_segment.with_generic_args(|generic_args| { + self.create_substs_for_ast_path( + span, + def_id, + generic_args, + item_segment.infer_types, + None, + ) + }); - assoc_bindings.first().map(|b| self.prohibit_projection(b.span)); + assoc_bindings.first().map(|b| Self::prohibit_assoc_ty_binding(self.tcx(), b.span)); substs } + /// Check that the correct number of generic arguments have been provided. + /// This is used both for type declarations and function calls. + pub fn check_generic_arg_count( + tcx: TyCtxt, + span: Span, + def: &ty::Generics, + args: &hir::GenericArgs, + is_declaration: bool, + is_method_call: bool, + has_self: bool, + infer_types: bool, + ) -> bool { + // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. + // that lifetimes will proceed types. So it suffices to check the number of each generic + // arguments in order to validate them with respect to the generic parameters. + let param_counts = def.own_counts(); + let arg_counts = args.own_counts(); + let infer_lifetimes = !is_declaration && arg_counts.lifetimes == 0; + + let mut defaults: ty::GenericParamCount = Default::default(); + for param in &def.params { + match param.kind { + GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Type { has_default, .. } => { + defaults.types += has_default as usize + } + }; + } + + if !is_declaration && !args.bindings.is_empty() { + AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); + } + + // Prohibit explicit lifetime arguments if late-bound lifetime parameters are present. + if !infer_lifetimes { + if let Some(span_late) = def.has_late_bound_regions { + let msg = "cannot specify lifetime arguments explicitly \ + if late bound lifetime parameters are present"; + let note = "the late bound lifetime parameter is introduced here"; + let span = args.args[0].span(); + if !is_method_call && arg_counts.lifetimes != param_counts.lifetimes { + let mut err = tcx.sess.struct_span_err(span, msg); + err.span_note(span_late, note); + err.emit(); + return true; + } else { + let mut multispan = MultiSpan::from_span(span); + multispan.push_span_label(span_late, note.to_string()); + tcx.lint_node(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, + args.args[0].id(), multispan, msg); + return false; + } + } + } + + let check_kind_count = |error_code_less: &str, + error_code_more: &str, + kind, + required, + permitted, + provided| { + // We enforce the following: `required` <= `provided` <= `permitted`. + // For kinds without defaults (i.e. lifetimes), `required == permitted`. + // For other kinds (i.e. types), `permitted` may be greater than `required`. + if required <= provided && provided <= permitted { + return false; + } + + // Unfortunately lifetime and type parameter mismatches are typically styled + // differently in diagnostics, which means we have a few cases to consider here. + let (bound, quantifier, suppress_error) = if required != permitted { + if provided < required { + (required, "at least ", false) + } else { // provided > permitted + (permitted, "at most ", true) + } + } else { + (required, "", false) + }; + let label = if required == permitted && provided > permitted { + let diff = provided - permitted; + format!( + "{}unexpected {} argument{}", + if diff != 1 { format!("{} ", diff) } else { String::new() }, + kind, + if diff != 1 { "s" } else { "" }, + ) + } else { + format!( + "expected {}{} {} argument{}", + quantifier, + bound, + kind, + if required != 1 { "s" } else { "" }, + ) + }; + + tcx.sess.struct_span_err_with_code( + span, + &format!( + "wrong number of {} arguments: expected {}{}, found {}", + kind, + quantifier, + bound, + provided, + ), + DiagnosticId::Error({ + if provided <= permitted { + error_code_less + } else { + error_code_more + } + }.into()) + ).span_label(span, label).emit(); + + suppress_error + }; + + if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { + check_kind_count( + "E0107", + "E0107", + "lifetime", + param_counts.lifetimes, + param_counts.lifetimes, + arg_counts.lifetimes, + ); + } + if !infer_types + || arg_counts.types > param_counts.types - defaults.types - has_self as usize { + check_kind_count( + "E0243", + "E0244", // FIXME: E0243 and E0244 should be unified. + "type", + param_counts.types - defaults.types - has_self as usize, + param_counts.types - has_self as usize, + arg_counts.types, + ) + } else { + false + } + } + /// Creates the relevant generic argument substitutions /// corresponding to a set of generic parameters. pub fn create_substs_for_generic_args<'a, 'b, A, P, I>( @@ -355,7 +499,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { assert_eq!(generic_params.has_self, self_ty.is_some()); let has_self = generic_params.has_self; - check_generic_arg_count(tcx, span, &generic_params, &generic_args, has_self, infer_types); + Self::check_generic_arg_count( + self.tcx(), + span, + &generic_params, + &generic_args, + true, // `is_declaration` + false, // `is_method_call` (irrelevant here) + has_self, + infer_types, + ); let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); let default_needs_object_self = |param: &ty::GenericParamDef| { @@ -548,7 +701,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { trait_def_id, self_ty, trait_segment); - assoc_bindings.first().map(|b| self.prohibit_projection(b.span)); + assoc_bindings.first().map(|b| AstConv::prohibit_assoc_ty_binding(self.tcx(), b.span)); ty::TraitRef::new(trait_def_id, substs) } @@ -1113,15 +1266,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } } for binding in &generic_args.bindings { - self.prohibit_projection(binding.span); + Self::prohibit_assoc_ty_binding(self.tcx(), binding.span); break; } }) } } - pub fn prohibit_projection(&self, span: Span) { - let mut err = struct_span_err!(self.tcx().sess, span, E0229, + pub fn prohibit_assoc_ty_binding(tcx: TyCtxt, span: Span) { + let mut err = struct_span_err!(tcx.sess, span, E0229, "associated type bindings are not allowed here"); err.span_label(span, "associated type not allowed here").emit(); } @@ -1497,109 +1650,6 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, (auto_traits, trait_bounds) } -pub fn check_generic_arg_count( - tcx: TyCtxt, - span: Span, - def: &ty::Generics, - args: &hir::GenericArgs, - has_self: bool, - infer_types: bool, -) { - // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. - // that lifetimes will proceed types. So it suffices to check the number of each generic - // arguments in order to validate them with respect to the generic parameters. - let param_counts = def.own_counts(); - let arg_counts = args.own_counts(); - - let mut defaults: ty::GenericParamCount = Default::default(); - for param in &def.params { - match param.kind { - GenericParamDefKind::Lifetime => {} - GenericParamDefKind::Type { has_default, .. } => defaults.types += has_default as usize, - }; - } - - let check_kind_count = |error_code_less: &str, - error_code_more: &str, - kind, - required, - permitted, - provided| { - // We enforce the following: `required` <= `provided` <= `permitted`. - // For kinds without defaults (i.e. lifetimes), `required == permitted`. - // For other kinds (i.e. types), `permitted` may be greater than `required`. - if required <= provided && provided <= permitted { - return; - } - - // Unfortunately lifetime and type parameter mismatches are typically styled - // differently in diagnostics, which means we have a few cases to consider here. - let (bound, quantifier) = if required != permitted { - if provided < required { - (required, "at least ") - } else { // provided > permitted - (permitted, "at most ") - } - } else { - (required, "") - }; - let label = if required == permitted && provided > permitted { - let diff = provided - permitted; - format!( - "{}unexpected {} argument{}", - if diff != 1 { format!("{} ", diff) } else { String::new() }, - kind, - if diff != 1 { "s" } else { "" }, - ) - } else { - format!( - "expected {}{} {} argument{}", - quantifier, - bound, - kind, - if required != 1 { "s" } else { "" }, - ) - }; - - tcx.sess.struct_span_err_with_code( - span, - &format!( - "wrong number of {} arguments: expected {}{}, found {}", - kind, - quantifier, - bound, - provided, - ), - DiagnosticId::Error({ - if provided <= permitted { - error_code_less - } else { - error_code_more - } - }.into()) - ).span_label(span, label).emit(); - }; - - check_kind_count( - "E0107", - "E0107", - "lifetime", - param_counts.lifetimes, - param_counts.lifetimes, - arg_counts.lifetimes, - ); - if !infer_types || arg_counts.types > param_counts.types - defaults.types - has_self as usize { - check_kind_count( - "E0243", - "E0244", // FIXME: E0243 and E0244 should be unified. - "type", - param_counts.types - defaults.types - has_self as usize, - param_counts.types - has_self as usize, - arg_counts.types, - ); - } -} - // A helper struct for conveniently grouping a set of bounds which we pass to // and return from functions in multiple places. #[derive(PartialEq, Eq, Clone, Debug)] diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 739c2013950c8..49225680432d9 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -14,6 +14,7 @@ use astconv::AstConv; use check::{FnCtxt, PlaceOp, callee, Needs}; use hir::GenericArg; use hir::def_id::DefId; +use hir::HirVec; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, GenericParamDefKind}; @@ -22,8 +23,9 @@ use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref}; use rustc::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk}; -use syntax_pos::Span; use rustc::hir; +use syntax_pos::Span; +use syntax::ptr::P; use std::ops::Deref; @@ -315,9 +317,21 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let method_generics = self.tcx.generics_of(pick.item.def_id); - let supress_mismatch = self.fcx.check_impl_trait(self.span, segment, &method_generics); - self.fcx.check_generic_arg_count(self.span, &segment, &method_generics, true, - supress_mismatch); + let suppress_mismatch = self.fcx.check_impl_trait(self.span, segment, &method_generics); + AstConv::check_generic_arg_count( + self.tcx, + self.span, + &method_generics, + &segment.args.clone().unwrap_or_else(|| P(hir::GenericArgs { + args: HirVec::new(), bindings: HirVec::new(), parenthesized: false, + })), + false, // `is_declaration` + true, // `is_method_call` + method_generics.parent.is_none() && method_generics.has_self, + segment.infer_types || suppress_mismatch, + ); + // self.fcx.check_generic_arg_count(self.span, &segment, &method_generics, true, + // supress_mismatch); // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f37ea81912231..ae5c0fc6fb14b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5168,7 +5168,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if !bindings.is_empty() { - AstConv::prohibit_projection(self, bindings[0].span); + AstConv::prohibit_assoc_ty_binding(self.tcx, bindings[0].span); } let infer_lifetimes = lifetimes.len() == 0; From 04d33bbdb3ca017a31f9f84218d894475a2d4a0a Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 8 Aug 2018 00:38:31 +0100 Subject: [PATCH 34/41] Refactor generic argument count check in check/mod.rs --- src/librustc_typeck/astconv.rs | 23 +-- src/librustc_typeck/check/method/confirm.rs | 8 +- src/librustc_typeck/check/mod.rs | 149 +++----------------- src/test/ui/error-codes/E0087.rs | 4 +- src/test/ui/error-codes/E0087.stderr | 16 +-- src/test/ui/error-codes/E0088.stderr | 12 +- src/test/ui/error-codes/E0089.rs | 2 +- src/test/ui/error-codes/E0089.stderr | 6 +- src/test/ui/error-codes/E0090.rs | 2 +- src/test/ui/error-codes/E0090.stderr | 6 +- 10 files changed, 65 insertions(+), 163 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 2e59c5959fbe5..3cd435e756e48 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -90,6 +90,11 @@ struct ConvertedBinding<'tcx> { span: Span, } +pub struct GenericArgMismatchErrorCode { + pub lifetimes: (&'static str, &'static str), + pub types: (&'static str, &'static str), +} + /// Dummy type used for the `Self` of a `TraitRef` created for converting /// a trait object, and which gets removed in `ExistentialTraitRef`. /// This type must not appear anywhere in other converted types. @@ -199,6 +204,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { is_method_call: bool, has_self: bool, infer_types: bool, + error_codes: GenericArgMismatchErrorCode, ) -> bool { // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. // that lifetimes will proceed types. So it suffices to check the number of each generic @@ -243,8 +249,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } } - let check_kind_count = |error_code_less: &str, - error_code_more: &str, + let check_kind_count = |error_code: (&str, &str), kind, required, permitted, @@ -296,9 +301,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { ), DiagnosticId::Error({ if provided <= permitted { - error_code_less + error_code.0 } else { - error_code_more + error_code.1 } }.into()) ).span_label(span, label).emit(); @@ -308,8 +313,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { check_kind_count( - "E0107", - "E0107", + error_codes.lifetimes, "lifetime", param_counts.lifetimes, param_counts.lifetimes, @@ -319,8 +323,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { if !infer_types || arg_counts.types > param_counts.types - defaults.types - has_self as usize { check_kind_count( - "E0243", - "E0244", // FIXME: E0243 and E0244 should be unified. + error_codes.types, "type", param_counts.types - defaults.types - has_self as usize, param_counts.types - has_self as usize, @@ -508,6 +511,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { false, // `is_method_call` (irrelevant here) has_self, infer_types, + GenericArgMismatchErrorCode { + lifetimes: ("E0107", "E0107"), + types: ("E0243", "E0244"), // FIXME: E0243 and E0244 should be unified. + }, ); let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 49225680432d9..88c540915af00 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -10,7 +10,7 @@ use super::{probe, MethodCallee}; -use astconv::AstConv; +use astconv::{AstConv, GenericArgMismatchErrorCode}; use check::{FnCtxt, PlaceOp, callee, Needs}; use hir::GenericArg; use hir::def_id::DefId; @@ -329,9 +329,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { true, // `is_method_call` method_generics.parent.is_none() && method_generics.has_self, segment.infer_types || suppress_mismatch, + GenericArgMismatchErrorCode { + lifetimes: ("E0090", "E0088"), + types: ("E0089", "E0087"), + }, ); - // self.fcx.check_generic_arg_count(self.span, &segment, &method_generics, true, - // supress_mismatch); // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ae5c0fc6fb14b..17adfda0bac0e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -84,9 +84,10 @@ pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::method::MethodCallee; use self::TupleArgumentsFlag::*; -use astconv::AstConv; +use astconv::{AstConv, GenericArgMismatchErrorCode}; use hir::GenericArg; use hir::def::Def; +use hir::HirVec; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use std::slice; use namespace::Namespace; @@ -4937,16 +4938,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // to add defaults. If the user provided *too many* types, that's // a problem. - let mut supress_errors = FxHashMap(); + let mut suppress_errors = FxHashMap(); for &PathSeg(def_id, index) in &path_segs { let seg = &segments[index]; let generics = self.tcx.generics_of(def_id); // `impl Trait` is treated as a normal generic parameter internally, // but we don't allow users to specify the parameter's value // explicitly, so we have to do some error-checking here. - let supress_mismatch = self.check_impl_trait(span, seg, &generics); - supress_errors.insert(index, - self.check_generic_arg_count(span, seg, &generics, false, supress_mismatch)); + let suppress_mismatch = self.check_impl_trait(span, seg, &generics); + suppress_errors.insert(index, AstConv::check_generic_arg_count( + self.tcx, + span, + &generics, + &seg.args.clone().unwrap_or_else(|| P(hir::GenericArgs { + args: HirVec::new(), bindings: HirVec::new(), parenthesized: false, + })), + false, // `is_declaration` + false, // `is_method_call` + generics.parent.is_none() && generics.has_self, + seg.infer_types || suppress_mismatch, + GenericArgMismatchErrorCode { + lifetimes: ("E0090", "E0088"), // FIXME: E0090 and E0088 should be unified. + types: ("E0089", "E0087"), // FIXME: E0089 and E0087 should be unified. + }, + )); } let has_self = path_segs.last().map(|PathSeg(def_id, _)| { @@ -4968,7 +4983,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) { // If we've encountered an `impl Trait`-related error, we're just // going to infer the arguments for better error messages. - if !supress_errors[&index] { + if !suppress_errors[&index] { // Check whether the user has provided generic arguments. if let Some(ref data) = segments[index].args { return (Some(data), segments[index].infer_types); @@ -5097,128 +5112,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { directly, not through a function pointer"); } - /// Report errors if the provided parameters are too few or too many. - fn check_generic_arg_count(&self, - span: Span, - segment: &hir::PathSegment, - generics: &ty::Generics, - is_method_call: bool, - supress_mismatch_error: bool) - -> bool { - let mut supress_errors = false; - let (mut lifetimes, mut types) = (vec![], vec![]); - let infer_types = segment.infer_types; - let mut bindings = vec![]; - if let Some(ref data) = segment.args { - data.args.iter().for_each(|arg| match arg { - GenericArg::Lifetime(lt) => lifetimes.push(lt.clone()), - GenericArg::Type(ty) => types.push(ty.clone()), - }); - bindings = data.bindings.clone().to_vec(); - } - - struct ParamRange { - required: usize, - accepted: usize - }; - - let mut lt_accepted = 0; - let mut ty_params = ParamRange { required: 0, accepted: 0 }; - for param in &generics.params { - match param.kind { - GenericParamDefKind::Lifetime => lt_accepted += 1, - GenericParamDefKind::Type { has_default, .. } => { - ty_params.accepted += 1; - if !has_default { - ty_params.required += 1; - } - } - }; - } - if generics.parent.is_none() && generics.has_self { - ty_params.required -= 1; - ty_params.accepted -= 1; - } - let ty_accepted = ty_params.accepted; - let ty_required = ty_params.required; - - let count_ty_params = |n| format!("{} type parameter{}", n, if n == 1 { "" } else { "s" }); - let expected_text = count_ty_params(ty_accepted); - let actual_text = count_ty_params(types.len()); - if let Some((mut err, span)) = if types.len() > ty_accepted { - // To prevent derived errors to accumulate due to extra - // type parameters, we force instantiate_value_path to - // use inference variables instead of the provided types. - supress_errors = true; - let span = types[ty_accepted].span; - Some((struct_span_err!(self.tcx.sess, span, E0087, - "too many type parameters provided: \ - expected at most {}, found {}", - expected_text, actual_text), span)) - } else if types.len() < ty_required && !infer_types && !supress_mismatch_error { - Some((struct_span_err!(self.tcx.sess, span, E0089, - "too few type parameters provided: \ - expected {}, found {}", - expected_text, actual_text), span)) - } else { - None - } { - self.set_tainted_by_errors(); // #53251 - err.span_label(span, format!("expected {}", expected_text)).emit(); - } - - if !bindings.is_empty() { - AstConv::prohibit_assoc_ty_binding(self.tcx, bindings[0].span); - } - - let infer_lifetimes = lifetimes.len() == 0; - // Prohibit explicit lifetime arguments if late bound lifetime parameters are present. - let has_late_bound_lifetime_defs = generics.has_late_bound_regions; - if let (Some(span_late), false) = (has_late_bound_lifetime_defs, lifetimes.is_empty()) { - // Report this as a lint only if no error was reported previously. - let primary_msg = "cannot specify lifetime arguments explicitly \ - if late bound lifetime parameters are present"; - let note_msg = "the late bound lifetime parameter is introduced here"; - if !is_method_call && (lifetimes.len() > lt_accepted || - lifetimes.len() < lt_accepted && !infer_lifetimes) { - supress_errors = true; - let mut err = self.tcx.sess.struct_span_err(lifetimes[0].span, primary_msg); - err.span_note(span_late, note_msg); - err.emit(); - } else { - let mut multispan = MultiSpan::from_span(lifetimes[0].span); - multispan.push_span_label(span_late, note_msg.to_string()); - self.tcx.lint_node(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, - lifetimes[0].id, multispan, primary_msg); - } - return supress_errors; - } - - let count_lifetime_params = |n| { - format!("{} lifetime parameter{}", n, if n == 1 { "" } else { "s" }) - }; - let expected_text = count_lifetime_params(lt_accepted); - let actual_text = count_lifetime_params(lifetimes.len()); - if let Some((mut err, span)) = if lifetimes.len() > lt_accepted { - let span = lifetimes[lt_accepted].span; - Some((struct_span_err!(self.tcx.sess, span, E0088, - "too many lifetime parameters provided: \ - expected at most {}, found {}", - expected_text, actual_text), span)) - } else if lifetimes.len() < lt_accepted && !infer_lifetimes { - Some((struct_span_err!(self.tcx.sess, span, E0090, - "too few lifetime parameters provided: \ - expected {}, found {}", - expected_text, actual_text), span)) - } else { - None - } { - err.span_label(span, format!("expected {}", expected_text)).emit(); - } - - supress_errors - } - /// Report error if there is an explicit type parameter when using `impl Trait`. fn check_impl_trait(&self, span: Span, diff --git a/src/test/ui/error-codes/E0087.rs b/src/test/ui/error-codes/E0087.rs index 6dc08860614d7..bea76f34220ef 100644 --- a/src/test/ui/error-codes/E0087.rs +++ b/src/test/ui/error-codes/E0087.rs @@ -12,7 +12,7 @@ fn foo() {} fn bar() {} fn main() { - foo::(); //~ ERROR expected at most 0 type parameters, found 1 type parameter [E0087] + foo::(); //~ ERROR wrong number of type arguments: expected 0, found 1 [E0087] - bar::(); //~ ERROR expected at most 1 type parameter, found 2 type parameters [E0087] + bar::(); //~ ERROR wrong number of type arguments: expected 1, found 2 [E0087] } diff --git a/src/test/ui/error-codes/E0087.stderr b/src/test/ui/error-codes/E0087.stderr index cd1e99e7b411a..7170a6f2cda12 100644 --- a/src/test/ui/error-codes/E0087.stderr +++ b/src/test/ui/error-codes/E0087.stderr @@ -1,14 +1,14 @@ -error[E0087]: too many type parameters provided: expected at most 0 type parameters, found 1 type parameter - --> $DIR/E0087.rs:15:11 +error[E0087]: wrong number of type arguments: expected 0, found 1 + --> $DIR/E0087.rs:15:5 | -LL | foo::(); //~ ERROR expected at most 0 type parameters, found 1 type parameter [E0087] - | ^^^ expected 0 type parameters +LL | foo::(); //~ ERROR wrong number of type arguments: expected 0, found 1 [E0087] + | ^^^^^^^^^^ unexpected type argument -error[E0087]: too many type parameters provided: expected at most 1 type parameter, found 2 type parameters - --> $DIR/E0087.rs:17:16 +error[E0087]: wrong number of type arguments: expected 1, found 2 + --> $DIR/E0087.rs:17:5 | -LL | bar::(); //~ ERROR expected at most 1 type parameter, found 2 type parameters [E0087] - | ^^^ expected 1 type parameter +LL | bar::(); //~ ERROR wrong number of type arguments: expected 1, found 2 [E0087] + | ^^^^^^^^^^^^^^^ unexpected type argument error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0088.stderr b/src/test/ui/error-codes/E0088.stderr index 4bf2760994eb7..4666702e1ebf3 100644 --- a/src/test/ui/error-codes/E0088.stderr +++ b/src/test/ui/error-codes/E0088.stderr @@ -1,14 +1,14 @@ -error[E0088]: too many lifetime parameters provided: expected at most 0 lifetime parameters, found 1 lifetime parameter - --> $DIR/E0088.rs:15:9 +error[E0088]: wrong number of lifetime arguments: expected 0, found 1 + --> $DIR/E0088.rs:15:5 | LL | f::<'static>(); //~ ERROR E0088 - | ^^^^^^^ expected 0 lifetime parameters + | ^^^^^^^^^^^^ unexpected lifetime argument -error[E0088]: too many lifetime parameters provided: expected at most 1 lifetime parameter, found 2 lifetime parameters - --> $DIR/E0088.rs:16:18 +error[E0088]: wrong number of lifetime arguments: expected 1, found 2 + --> $DIR/E0088.rs:16:5 | LL | g::<'static, 'static>(); //~ ERROR E0088 - | ^^^^^^^ expected 1 lifetime parameter + | ^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0089.rs b/src/test/ui/error-codes/E0089.rs index 21df9abd0932e..4e6196a7b89db 100644 --- a/src/test/ui/error-codes/E0089.rs +++ b/src/test/ui/error-codes/E0089.rs @@ -11,5 +11,5 @@ fn foo() {} fn main() { - foo::(); //~ ERROR expected 2 type parameters, found 1 type parameter [E0089] + foo::(); //~ ERROR wrong number of type arguments: expected 2, found 1 [E0089] } diff --git a/src/test/ui/error-codes/E0089.stderr b/src/test/ui/error-codes/E0089.stderr index 0b95033fb3606..f79c478b733f6 100644 --- a/src/test/ui/error-codes/E0089.stderr +++ b/src/test/ui/error-codes/E0089.stderr @@ -1,8 +1,8 @@ -error[E0089]: too few type parameters provided: expected 2 type parameters, found 1 type parameter +error[E0089]: wrong number of type arguments: expected 2, found 1 --> $DIR/E0089.rs:14:5 | -LL | foo::(); //~ ERROR expected 2 type parameters, found 1 type parameter [E0089] - | ^^^^^^^^^^ expected 2 type parameters +LL | foo::(); //~ ERROR wrong number of type arguments: expected 2, found 1 [E0089] + | ^^^^^^^^^^ expected 2 type arguments error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0090.rs b/src/test/ui/error-codes/E0090.rs index 13b2131cc8be0..26be4c12f075e 100644 --- a/src/test/ui/error-codes/E0090.rs +++ b/src/test/ui/error-codes/E0090.rs @@ -11,5 +11,5 @@ fn foo<'a: 'b, 'b: 'a>() {} fn main() { - foo::<'static>(); //~ ERROR expected 2 lifetime parameters, found 1 lifetime parameter [E0090] + foo::<'static>(); //~ ERROR wrong number of lifetime arguments: expected 2, found 1 [E0090] } diff --git a/src/test/ui/error-codes/E0090.stderr b/src/test/ui/error-codes/E0090.stderr index f119d5fa46719..9029b6c2708bd 100644 --- a/src/test/ui/error-codes/E0090.stderr +++ b/src/test/ui/error-codes/E0090.stderr @@ -1,8 +1,8 @@ -error[E0090]: too few lifetime parameters provided: expected 2 lifetime parameters, found 1 lifetime parameter +error[E0090]: wrong number of lifetime arguments: expected 2, found 1 --> $DIR/E0090.rs:14:5 | -LL | foo::<'static>(); //~ ERROR expected 2 lifetime parameters, found 1 lifetime parameter [E0090] - | ^^^^^^^^^^^^^^ expected 2 lifetime parameters +LL | foo::<'static>(); //~ ERROR wrong number of lifetime arguments: expected 2, found 1 [E0090] + | ^^^^^^^^^^^^^^ expected 2 lifetime arguments error: aborting due to previous error From 03c4628a5b71af301ccf51d9b1b6ab2207b1fcca Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 8 Aug 2018 01:18:03 +0100 Subject: [PATCH 35/41] Avoid clone and update documentation --- src/librustc_typeck/astconv.rs | 73 +++++++++++++++++++-- src/librustc_typeck/check/method/confirm.rs | 28 +++----- src/librustc_typeck/check/mod.rs | 46 +------------ src/librustc_typeck/diagnostics.rs | 30 +++++---- 4 files changed, 97 insertions(+), 80 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3cd435e756e48..2573a967985a5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -17,6 +17,7 @@ use rustc_data_structures::array_vec::ArrayVec; use hir::{self, GenericArg, GenericArgs}; use hir::def::Def; use hir::def_id::DefId; +use hir::HirVec; use middle::resolve_lifetime as rl; use namespace::Namespace; use rustc::ty::subst::{Kind, Subst, Substs}; @@ -34,6 +35,7 @@ use lint; use std::iter; use syntax::ast; +use syntax::ptr::P; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax_pos::{Span, MultiSpan}; @@ -90,9 +92,9 @@ struct ConvertedBinding<'tcx> { span: Span, } -pub struct GenericArgMismatchErrorCode { - pub lifetimes: (&'static str, &'static str), - pub types: (&'static str, &'static str), +struct GenericArgMismatchErrorCode { + lifetimes: (&'static str, &'static str), + types: (&'static str, &'static str), } /// Dummy type used for the `Self` of a `TraitRef` created for converting @@ -193,9 +195,72 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { substs } + /// Report error if there is an explicit type parameter when using `impl Trait`. + fn check_impl_trait( + tcx: TyCtxt, + span: Span, + seg: &hir::PathSegment, + generics: &ty::Generics, + ) -> bool { + let explicit = !seg.infer_types; + let impl_trait = generics.params.iter().any(|param| match param.kind { + ty::GenericParamDefKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. + } => true, + _ => false, + }); + + if explicit && impl_trait { + let mut err = struct_span_err! { + tcx.sess, + span, + E0632, + "cannot provide explicit type parameters when `impl Trait` is \ + used in argument position." + }; + + err.emit(); + } + + impl_trait + } + + /// Check that the correct number of generic arguments have been provided. + /// Used specifically for function calls. + pub fn check_generic_arg_count_for_call( + tcx: TyCtxt, + span: Span, + def: &ty::Generics, + seg: &hir::PathSegment, + is_method_call: bool, + ) -> bool { + let empty_args = P(hir::GenericArgs { + args: HirVec::new(), bindings: HirVec::new(), parenthesized: false, + }); + let suppress_mismatch = Self::check_impl_trait(tcx, span, seg, &def); + Self::check_generic_arg_count( + tcx, + span, + def, + if let Some(ref args) = seg.args { + args + } else { + &empty_args + }, + false, // `is_declaration` + is_method_call, + def.parent.is_none() && def.has_self, // `has_self` + seg.infer_types || suppress_mismatch, // `infer_types` + GenericArgMismatchErrorCode { + lifetimes: ("E0090", "E0088"), + types: ("E0089", "E0087"), + }, + ) + } + /// Check that the correct number of generic arguments have been provided. /// This is used both for type declarations and function calls. - pub fn check_generic_arg_count( + fn check_generic_arg_count( tcx: TyCtxt, span: Span, def: &ty::Generics, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 88c540915af00..e848508b8c04d 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -10,11 +10,10 @@ use super::{probe, MethodCallee}; -use astconv::{AstConv, GenericArgMismatchErrorCode}; +use astconv::AstConv; use check::{FnCtxt, PlaceOp, callee, Needs}; use hir::GenericArg; use hir::def_id::DefId; -use hir::HirVec; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, GenericParamDefKind}; @@ -25,7 +24,6 @@ use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk}; use rustc::hir; use syntax_pos::Span; -use syntax::ptr::P; use std::ops::Deref; @@ -310,34 +308,24 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_substs( &mut self, pick: &probe::Pick<'tcx>, - segment: &hir::PathSegment, + seg: &hir::PathSegment, parent_substs: &Substs<'tcx>, ) -> &'tcx Substs<'tcx> { // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh // variables. - let method_generics = self.tcx.generics_of(pick.item.def_id); - let suppress_mismatch = self.fcx.check_impl_trait(self.span, segment, &method_generics); - AstConv::check_generic_arg_count( + let generics = self.tcx.generics_of(pick.item.def_id); + AstConv::check_generic_arg_count_for_call( self.tcx, self.span, - &method_generics, - &segment.args.clone().unwrap_or_else(|| P(hir::GenericArgs { - args: HirVec::new(), bindings: HirVec::new(), parenthesized: false, - })), - false, // `is_declaration` + &generics, + &seg, true, // `is_method_call` - method_generics.parent.is_none() && method_generics.has_self, - segment.infer_types || suppress_mismatch, - GenericArgMismatchErrorCode { - lifetimes: ("E0090", "E0088"), - types: ("E0089", "E0087"), - }, ); // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. - assert_eq!(method_generics.parent_count, parent_substs.len()); + assert_eq!(generics.parent_count, parent_substs.len()); AstConv::create_substs_for_generic_args( self.tcx, @@ -348,7 +336,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Provide the generic args, and whether types should be inferred. |_| { // The last argument of the returned tuple here is unimportant. - if let Some(ref data) = segment.args { + if let Some(ref data) = seg.args { (Some(data), false) } else { (None, false) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 17adfda0bac0e..3ed42b6b2617b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -84,10 +84,9 @@ pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::method::MethodCallee; use self::TupleArgumentsFlag::*; -use astconv::{AstConv, GenericArgMismatchErrorCode}; +use astconv::AstConv; use hir::GenericArg; use hir::def::Def; -use hir::HirVec; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use std::slice; use namespace::Namespace; @@ -4945,22 +4944,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `impl Trait` is treated as a normal generic parameter internally, // but we don't allow users to specify the parameter's value // explicitly, so we have to do some error-checking here. - let suppress_mismatch = self.check_impl_trait(span, seg, &generics); - suppress_errors.insert(index, AstConv::check_generic_arg_count( + suppress_errors.insert(index, AstConv::check_generic_arg_count_for_call( self.tcx, span, &generics, - &seg.args.clone().unwrap_or_else(|| P(hir::GenericArgs { - args: HirVec::new(), bindings: HirVec::new(), parenthesized: false, - })), - false, // `is_declaration` + &seg, false, // `is_method_call` - generics.parent.is_none() && generics.has_self, - seg.infer_types || suppress_mismatch, - GenericArgMismatchErrorCode { - lifetimes: ("E0090", "E0088"), // FIXME: E0090 and E0088 should be unified. - types: ("E0089", "E0087"), // FIXME: E0089 and E0087 should be unified. - }, )); } @@ -5112,35 +5101,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { directly, not through a function pointer"); } - /// Report error if there is an explicit type parameter when using `impl Trait`. - fn check_impl_trait(&self, - span: Span, - seg: &hir::PathSegment, - generics: &ty::Generics) - -> bool { - let explicit = !seg.infer_types; - let impl_trait = generics.params.iter().any(|param| match param.kind { - ty::GenericParamDefKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. - } => true, - _ => false, - }); - - if explicit && impl_trait { - let mut err = struct_span_err! { - self.tcx.sess, - span, - E0632, - "cannot provide explicit type parameters when `impl Trait` is \ - used in argument position." - }; - - err.emit(); - } - - impl_trait - } - // Resolves `typ` by a single level if `typ` is a type variable. // If no resolution is possible, then an error is reported. // Numeric inference variables may be left unresolved. diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 4d957c9aa4520..c01102272aeb4 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1041,32 +1041,34 @@ enum NightsWatch {} "##, E0087: r##" -Too many type parameters were supplied for a function. For example: +Too many type arguments were supplied for a function. For example: ```compile_fail,E0087 fn foo() {} fn main() { - foo::(); // error, expected 1 parameter, found 2 parameters + foo::(); // error: wrong number of type arguments: + // expected 1, found 2 } ``` -The number of supplied parameters must exactly match the number of defined type +The number of supplied arguments must exactly match the number of defined type parameters. "##, E0088: r##" -You gave too many lifetime parameters. Erroneous code example: +You gave too many lifetime arguments. Erroneous code example: ```compile_fail,E0088 fn f() {} fn main() { - f::<'static>() // error: too many lifetime parameters provided + f::<'static>() // error: wrong number of lifetime arguments: + // expected 0, found 1 } ``` -Please check you give the right number of lifetime parameters. Example: +Please check you give the right number of lifetime arguments. Example: ``` fn f() {} @@ -1101,17 +1103,17 @@ fn main() { "##, E0089: r##" -Not enough type parameters were supplied for a function. For example: +Too few type arguments were supplied for a function. For example: ```compile_fail,E0089 fn foo() {} fn main() { - foo::(); // error, expected 2 parameters, found 1 parameter + foo::(); // error: wrong number of type arguments: expected 2, found 1 } ``` -Note that if a function takes multiple type parameters but you want the compiler +Note that if a function takes multiple type arguments but you want the compiler to infer some of them, you can use type placeholders: ```compile_fail,E0089 @@ -1119,24 +1121,26 @@ fn foo(x: T) {} fn main() { let x: bool = true; - foo::(x); // error, expected 2 parameters, found 1 parameter + foo::(x); // error: wrong number of type arguments: + // expected 2, found 1 foo::<_, f64>(x); // same as `foo::(x)` } ``` "##, E0090: r##" -You gave too few lifetime parameters. Example: +You gave too few lifetime arguments. Example: ```compile_fail,E0090 fn foo<'a: 'b, 'b: 'a>() {} fn main() { - foo::<'static>(); // error, expected 2 lifetime parameters + foo::<'static>(); // error: wrong number of lifetime arguments: + // expected 2, found 1 } ``` -Please check you give the right number of lifetime parameters. Example: +Please check you give the right number of lifetime arguments. Example: ``` fn foo<'a: 'b, 'b: 'a>() {} From 4722744e4d0ff1dbc65f906bc5a21ada7581ce24 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 8 Aug 2018 01:46:00 +0100 Subject: [PATCH 36/41] Fix some remaining tests --- src/librustc_typeck/astconv.rs | 40 ++++++++++++------- src/test/ui/bad/bad-mid-path-type-params.rs | 6 +-- src/test/ui/constructor-lifetime-args.rs | 8 ++-- .../methods/method-call-lifetime-args-fail.rs | 8 ++-- src/test/ui/traits/trait-test-2.rs | 4 +- src/test/ui/ufcs/ufcs-qpath-missing-params.rs | 2 +- 6 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 2573a967985a5..4af8dd982a7fd 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -92,6 +92,13 @@ struct ConvertedBinding<'tcx> { span: Span, } +#[derive(PartialEq)] +enum GenericArgPosition { + Datatype, + Function, + Method, +} + struct GenericArgMismatchErrorCode { lifetimes: (&'static str, &'static str), types: (&'static str, &'static str), @@ -247,8 +254,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } else { &empty_args }, - false, // `is_declaration` - is_method_call, + if is_method_call { + GenericArgPosition::Method + } else { + GenericArgPosition::Function + }, def.parent.is_none() && def.has_self, // `has_self` seg.infer_types || suppress_mismatch, // `infer_types` GenericArgMismatchErrorCode { @@ -259,14 +269,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } /// Check that the correct number of generic arguments have been provided. - /// This is used both for type declarations and function calls. + /// This is used both for datatypes and function calls. fn check_generic_arg_count( tcx: TyCtxt, span: Span, def: &ty::Generics, args: &hir::GenericArgs, - is_declaration: bool, - is_method_call: bool, + position: GenericArgPosition, has_self: bool, infer_types: bool, error_codes: GenericArgMismatchErrorCode, @@ -276,7 +285,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // arguments in order to validate them with respect to the generic parameters. let param_counts = def.own_counts(); let arg_counts = args.own_counts(); - let infer_lifetimes = !is_declaration && arg_counts.lifetimes == 0; + let infer_lifetimes = position != GenericArgPosition::Datatype && arg_counts.lifetimes == 0; let mut defaults: ty::GenericParamCount = Default::default(); for param in &def.params { @@ -288,7 +297,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { }; } - if !is_declaration && !args.bindings.is_empty() { + if position != GenericArgPosition::Datatype && !args.bindings.is_empty() { AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); } @@ -299,7 +308,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { if late bound lifetime parameters are present"; let note = "the late bound lifetime parameter is introduced here"; let span = args.args[0].span(); - if !is_method_call && arg_counts.lifetimes != param_counts.lifetimes { + if position == GenericArgPosition::Function + && arg_counts.lifetimes != param_counts.lifetimes { let mut err = tcx.sess.struct_span_err(span, msg); err.span_note(span_late, note); err.emit(); @@ -328,15 +338,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // Unfortunately lifetime and type parameter mismatches are typically styled // differently in diagnostics, which means we have a few cases to consider here. - let (bound, quantifier, suppress_error) = if required != permitted { + let (bound, quantifier) = if required != permitted { if provided < required { - (required, "at least ", false) + (required, "at least ") } else { // provided > permitted - (permitted, "at most ", true) + (permitted, "at most ") } } else { - (required, "", false) + (required, "") }; + let label = if required == permitted && provided > permitted { let diff = provided - permitted; format!( @@ -373,7 +384,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { }.into()) ).span_label(span, label).emit(); - suppress_error + provided > required // `suppress_error` }; if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { @@ -572,8 +583,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { span, &generic_params, &generic_args, - true, // `is_declaration` - false, // `is_method_call` (irrelevant here) + GenericArgPosition::Datatype, has_self, infer_types, GenericArgMismatchErrorCode { diff --git a/src/test/ui/bad/bad-mid-path-type-params.rs b/src/test/ui/bad/bad-mid-path-type-params.rs index 4645142ea66fa..1ee70d9bddea0 100644 --- a/src/test/ui/bad/bad-mid-path-type-params.rs +++ b/src/test/ui/bad/bad-mid-path-type-params.rs @@ -38,16 +38,16 @@ impl Trait for S2 { fn foo<'a>() { let _ = S::new::(1, 1.0); - //~^ ERROR too many type parameters provided + //~^ ERROR wrong number of type arguments let _ = S::<'a,isize>::new::(1, 1.0); //~^ ERROR wrong number of lifetime arguments let _: S2 = Trait::new::(1, 1.0); - //~^ ERROR too many type parameters provided + //~^ ERROR wrong number of type arguments let _: S2 = Trait::<'a,isize>::new::(1, 1.0); - //~^ ERROR too many lifetime parameters provided + //~^ ERROR wrong number of lifetime arguments } fn main() {} diff --git a/src/test/ui/constructor-lifetime-args.rs b/src/test/ui/constructor-lifetime-args.rs index 50db9707355f4..1fe50cfebbac3 100644 --- a/src/test/ui/constructor-lifetime-args.rs +++ b/src/test/ui/constructor-lifetime-args.rs @@ -25,12 +25,12 @@ enum E<'a, 'b> { fn main() { S(&0, &0); // OK S::<'static>(&0, &0); - //~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter + //~^ ERROR wrong number of lifetime arguments: expected 2, found 1 S::<'static, 'static, 'static>(&0, &0); - //~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters + //~^ ERROR wrong number of lifetime arguments: expected 2, found 3 E::V(&0); // OK E::V::<'static>(&0); - //~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter + //~^ ERROR wrong number of lifetime arguments: expected 2, found 1 E::V::<'static, 'static, 'static>(&0); - //~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters + //~^ ERROR wrong number of lifetime arguments: expected 2, found 3 } diff --git a/src/test/ui/methods/method-call-lifetime-args-fail.rs b/src/test/ui/methods/method-call-lifetime-args-fail.rs index f0a87c7470386..980ada9020c48 100644 --- a/src/test/ui/methods/method-call-lifetime-args-fail.rs +++ b/src/test/ui/methods/method-call-lifetime-args-fail.rs @@ -24,9 +24,9 @@ impl S { fn method_call() { S.early(); // OK S.early::<'static>(); - //~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter + //~^ ERROR wrong number of lifetime arguments: expected 2, found 1 S.early::<'static, 'static, 'static>(); - //~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters + //~^ ERROR wrong number of lifetime arguments: expected 2, found 3 let _: &u8 = S.life_and_type::<'static>(); S.life_and_type::(); S.life_and_type::<'static, u8>(); @@ -71,9 +71,9 @@ fn ufcs() { S::early(S); // OK S::early::<'static>(S); - //~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter + //~^ ERROR wrong number of lifetime arguments: expected 2, found 1 S::early::<'static, 'static, 'static>(S); - //~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters + //~^ ERROR wrong number of lifetime arguments: expected 2, found 3 let _: &u8 = S::life_and_type::<'static>(S); S::life_and_type::(S); S::life_and_type::<'static, u8>(S); diff --git a/src/test/ui/traits/trait-test-2.rs b/src/test/ui/traits/trait-test-2.rs index b08aab6da852a..dac76fb57fd7c 100644 --- a/src/test/ui/traits/trait-test-2.rs +++ b/src/test/ui/traits/trait-test-2.rs @@ -15,8 +15,8 @@ impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } fn main() { - 10.dup::(); //~ ERROR expected at most 0 type parameters, found 1 type parameter - 10.blah::(); //~ ERROR expected at most 1 type parameter, found 2 type parameters + 10.dup::(); //~ ERROR wrong number of type arguments: expected 0, found 1 + 10.blah::(); //~ ERROR wrong number of type arguments: expected 1, found 2 (box 10 as Box).dup(); //~^ ERROR E0038 //~| ERROR E0038 diff --git a/src/test/ui/ufcs/ufcs-qpath-missing-params.rs b/src/test/ui/ufcs/ufcs-qpath-missing-params.rs index 5c108e052160c..294a0fa0340cc 100644 --- a/src/test/ui/ufcs/ufcs-qpath-missing-params.rs +++ b/src/test/ui/ufcs/ufcs-qpath-missing-params.rs @@ -22,5 +22,5 @@ impl<'a> IntoCow<'a, str> for String { fn main() { ::into_cow("foo".to_string()); - //~^ ERROR too few type parameters provided: expected 1 type parameter + //~^ ERROR wrong number of type arguments: expected 1, found 0 } From 25b62679e93745a9c2e552810ee1bd0edeaadcdc Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 19 Aug 2018 20:33:38 +0100 Subject: [PATCH 37/41] Taking a peek --- src/librustc_typeck/astconv.rs | 31 +++++++++++++++---------------- src/librustc_typeck/check/mod.rs | 2 +- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 4af8dd982a7fd..c7926cbaa6906 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -455,14 +455,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // Iterate over each segment of the path. while let Some((def_id, defs)) = stack.pop() { - let mut params = defs.params.iter(); - let mut next_param = params.next(); + let mut params = defs.params.iter().peekable(); // If we have already computed substitutions for parents, we can use those directly. - while let Some(param) = next_param { + while let Some(¶m) = params.peek() { if let Some(&kind) = parent_substs.get(param.index as usize) { push_kind(&mut substs, kind); - next_param = params.next(); + params.next(); } else { break; } @@ -470,12 +469,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // (Unless it's been handled in `parent_substs`) `Self` is handled first. if has_self { - if let Some(param) = next_param { + if let Some(¶m) = params.peek() { if param.index == 0 { if let GenericParamDefKind::Type { .. } = param.kind { push_kind(&mut substs, self_ty.map(|ty| ty.into()) .unwrap_or_else(|| inferred_kind(None, param, true))); - next_param = params.next(); + params.next(); } } } @@ -484,8 +483,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // Check whether this segment takes generic arguments and the user has provided any. let (generic_args, infer_types) = args_for_def_id(def_id); - let mut args = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()); - let mut next_arg = args.next(); + let mut args = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()) + .peekable(); loop { // We're going to iterate through the generic arguments that the user @@ -493,12 +492,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // Mismatches can occur as a result of elided lifetimes, or for malformed // input. We try to handle both sensibly. let mut progress_arg = true; - match (next_arg, next_param) { - (Some(arg), Some(param)) => { + match (args.peek(), params.peek()) { + (Some(&arg), Some(¶m)) => { match (arg, ¶m.kind) { (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime) => { push_kind(&mut substs, provided_kind(param, arg)); - next_param = params.next(); + params.next(); } (GenericArg::Lifetime(_), GenericParamDefKind::Type { .. }) => { // We expected a type argument, but got a lifetime @@ -510,13 +509,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } (GenericArg::Type(_), GenericParamDefKind::Type { .. }) => { push_kind(&mut substs, provided_kind(param, arg)); - next_param = params.next(); + params.next(); } (GenericArg::Type(_), GenericParamDefKind::Lifetime) => { // We expected a lifetime argument, but got a type // argument. That means we're inferring the lifetimes. push_kind(&mut substs, inferred_kind(None, param, infer_types)); - next_param = params.next(); + params.next(); progress_arg = false; } } @@ -526,7 +525,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // Getting to this point means the user supplied more arguments than // there are parameters. } - (None, Some(param)) => { + (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. match param.kind { @@ -538,12 +537,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { push_kind(&mut substs, kind); } } - next_param = params.next(); + params.next(); } (None, None) => break, } if progress_arg { - next_arg = args.next(); + args.next(); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3ed42b6b2617b..6d4d5188e3147 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4832,7 +4832,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::VariantCtor(def_id, ..) => { // Everything but the final segment should have no // parameters at all. - let mut generics = self.tcx.generics_of(def_id); + let generics = self.tcx.generics_of(def_id); // Variant and struct constructors use the // generics of their parent type definition. let generics_def_id = generics.parent.unwrap_or(def_id); From b5c2470ba3a3cb94450a522af34aabd20f1cb7b4 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Aug 2018 00:08:01 +0100 Subject: [PATCH 38/41] Update new ui tests --- .../ui/bad/bad-mid-path-type-params.stderr | 22 +++++++++---------- src/test/ui/constructor-lifetime-args.stderr | 20 ++++++++--------- ...eric-impl-more-params-with-defaults.stderr | 2 +- src/test/ui/issue-53251.rs | 4 +++- .../method-call-lifetime-args-fail.stderr | 20 ++++++++--------- src/test/ui/seq-args.stderr | 4 ++-- ...structure-constructor-type-mismatch.stderr | 4 ++-- .../ui/traits/trait-object-vs-lifetime.stderr | 4 ++-- src/test/ui/traits/trait-test-2.stderr | 16 +++++++------- .../ui/ufcs/ufcs-qpath-missing-params.stderr | 4 ++-- .../unboxed-closure-sugar-region.stderr | 4 ++-- ...wrong-number-number-type-parameters.stderr | 2 +- 12 files changed, 54 insertions(+), 52 deletions(-) diff --git a/src/test/ui/bad/bad-mid-path-type-params.stderr b/src/test/ui/bad/bad-mid-path-type-params.stderr index d2b002ebee92c..f0998b23c1c60 100644 --- a/src/test/ui/bad/bad-mid-path-type-params.stderr +++ b/src/test/ui/bad/bad-mid-path-type-params.stderr @@ -1,26 +1,26 @@ -error[E0087]: too many type parameters provided: expected at most 1 type parameter, found 2 type parameters - --> $DIR/bad-mid-path-type-params.rs:40:28 +error[E0087]: wrong number of type arguments: expected 1, found 2 + --> $DIR/bad-mid-path-type-params.rs:40:13 | LL | let _ = S::new::(1, 1.0); - | ^^^ expected 1 type parameter + | ^^^^^^^^^^^^^^^^^^^ unexpected type argument -error[E0107]: wrong number of lifetime parameters: expected 0, found 1 +error[E0107]: wrong number of lifetime arguments: expected 0, found 1 --> $DIR/bad-mid-path-type-params.rs:43:13 | LL | let _ = S::<'a,isize>::new::(1, 1.0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime parameter + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument -error[E0087]: too many type parameters provided: expected at most 1 type parameter, found 2 type parameters - --> $DIR/bad-mid-path-type-params.rs:46:36 +error[E0087]: wrong number of type arguments: expected 1, found 2 + --> $DIR/bad-mid-path-type-params.rs:46:17 | LL | let _: S2 = Trait::new::(1, 1.0); - | ^^^ expected 1 type parameter + | ^^^^^^^^^^^^^^^^^^^^^^^ unexpected type argument -error[E0088]: too many lifetime parameters provided: expected at most 0 lifetime parameters, found 1 lifetime parameter - --> $DIR/bad-mid-path-type-params.rs:49:25 +error[E0088]: wrong number of lifetime arguments: expected 0, found 1 + --> $DIR/bad-mid-path-type-params.rs:49:17 | LL | let _: S2 = Trait::<'a,isize>::new::(1, 1.0); - | ^^ expected 0 lifetime parameters + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument error: aborting due to 4 previous errors diff --git a/src/test/ui/constructor-lifetime-args.stderr b/src/test/ui/constructor-lifetime-args.stderr index 1710594d255e7..930d90c70bda5 100644 --- a/src/test/ui/constructor-lifetime-args.stderr +++ b/src/test/ui/constructor-lifetime-args.stderr @@ -1,26 +1,26 @@ -error[E0090]: too few lifetime parameters provided: expected 2 lifetime parameters, found 1 lifetime parameter +error[E0090]: wrong number of lifetime arguments: expected 2, found 1 --> $DIR/constructor-lifetime-args.rs:27:5 | LL | S::<'static>(&0, &0); - | ^^^^^^^^^^^^ expected 2 lifetime parameters + | ^^^^^^^^^^^^ expected 2 lifetime arguments -error[E0088]: too many lifetime parameters provided: expected at most 2 lifetime parameters, found 3 lifetime parameters - --> $DIR/constructor-lifetime-args.rs:29:27 +error[E0088]: wrong number of lifetime arguments: expected 2, found 3 + --> $DIR/constructor-lifetime-args.rs:29:5 | LL | S::<'static, 'static, 'static>(&0, &0); - | ^^^^^^^ expected 2 lifetime parameters + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument -error[E0090]: too few lifetime parameters provided: expected 2 lifetime parameters, found 1 lifetime parameter +error[E0090]: wrong number of lifetime arguments: expected 2, found 1 --> $DIR/constructor-lifetime-args.rs:32:5 | LL | E::V::<'static>(&0); - | ^^^^^^^^^^^^^^^ expected 2 lifetime parameters + | ^^^^^^^^^^^^^^^ expected 2 lifetime arguments -error[E0088]: too many lifetime parameters provided: expected at most 2 lifetime parameters, found 3 lifetime parameters - --> $DIR/constructor-lifetime-args.rs:34:30 +error[E0088]: wrong number of lifetime arguments: expected 2, found 3 + --> $DIR/constructor-lifetime-args.rs:34:5 | LL | E::V::<'static, 'static, 'static>(&0); - | ^^^^^^^ expected 2 lifetime parameters + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument error: aborting due to 4 previous errors diff --git a/src/test/ui/generic/generic-impl-more-params-with-defaults.stderr b/src/test/ui/generic/generic-impl-more-params-with-defaults.stderr index 6b54baefb1dd3..b614da88ba164 100644 --- a/src/test/ui/generic/generic-impl-more-params-with-defaults.stderr +++ b/src/test/ui/generic/generic-impl-more-params-with-defaults.stderr @@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected at most 2, found 3 --> $DIR/generic-impl-more-params-with-defaults.rs:23:5 | LL | Vec::::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 2 type arguments + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 2 type argument error: aborting due to previous error diff --git a/src/test/ui/issue-53251.rs b/src/test/ui/issue-53251.rs index aa9da744566f7..8c75ea45a6170 100644 --- a/src/test/ui/issue-53251.rs +++ b/src/test/ui/issue-53251.rs @@ -19,10 +19,12 @@ macro_rules! impl_add { $( fn $n() { S::f::(); - //~^ ERROR too many type parameters provided + //~^ ERROR wrong number of type arguments } )* } } impl_add!(a b); + +fn main() {} diff --git a/src/test/ui/methods/method-call-lifetime-args-fail.stderr b/src/test/ui/methods/method-call-lifetime-args-fail.stderr index 3814f4b5065ba..849fa574e127c 100644 --- a/src/test/ui/methods/method-call-lifetime-args-fail.stderr +++ b/src/test/ui/methods/method-call-lifetime-args-fail.stderr @@ -1,14 +1,14 @@ -error[E0090]: too few lifetime parameters provided: expected 2 lifetime parameters, found 1 lifetime parameter +error[E0090]: wrong number of lifetime arguments: expected 2, found 1 --> $DIR/method-call-lifetime-args-fail.rs:26:7 | LL | S.early::<'static>(); - | ^^^^^ expected 2 lifetime parameters + | ^^^^^ expected 2 lifetime arguments -error[E0088]: too many lifetime parameters provided: expected at most 2 lifetime parameters, found 3 lifetime parameters - --> $DIR/method-call-lifetime-args-fail.rs:28:33 +error[E0088]: wrong number of lifetime arguments: expected 2, found 3 + --> $DIR/method-call-lifetime-args-fail.rs:28:7 | LL | S.early::<'static, 'static, 'static>(); - | ^^^^^^^ expected 2 lifetime parameters + | ^^^^^ unexpected lifetime argument error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:37:15 @@ -178,17 +178,17 @@ note: the late bound lifetime parameter is introduced here LL | fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} } | ^^ -error[E0090]: too few lifetime parameters provided: expected 2 lifetime parameters, found 1 lifetime parameter +error[E0090]: wrong number of lifetime arguments: expected 2, found 1 --> $DIR/method-call-lifetime-args-fail.rs:73:5 | LL | S::early::<'static>(S); - | ^^^^^^^^^^^^^^^^^^^ expected 2 lifetime parameters + | ^^^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments -error[E0088]: too many lifetime parameters provided: expected at most 2 lifetime parameters, found 3 lifetime parameters - --> $DIR/method-call-lifetime-args-fail.rs:75:34 +error[E0088]: wrong number of lifetime arguments: expected 2, found 3 + --> $DIR/method-call-lifetime-args-fail.rs:75:5 | LL | S::early::<'static, 'static, 'static>(S); - | ^^^^^^^ expected 2 lifetime parameters + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument error: aborting due to 18 previous errors diff --git a/src/test/ui/seq-args.stderr b/src/test/ui/seq-args.stderr index dc9d0a7fc0baf..0a68c9b917fc1 100644 --- a/src/test/ui/seq-args.stderr +++ b/src/test/ui/seq-args.stderr @@ -2,13 +2,13 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/seq-args.rs:14:9 | LL | impl seq for Vec { //~ ERROR wrong number of type arguments - | ^^^^^^ expected no type arguments + | ^^^^^^ unexpected type argument error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/seq-args.rs:17:6 | LL | impl seq for u32 { //~ ERROR wrong number of type arguments - | ^^^^^^^^^ expected no type arguments + | ^^^^^^^^^ unexpected type argument error: aborting due to 2 previous errors diff --git a/src/test/ui/structs/structure-constructor-type-mismatch.stderr b/src/test/ui/structs/structure-constructor-type-mismatch.stderr index 1a88bc09dd6e9..88e3b85bca5dc 100644 --- a/src/test/ui/structs/structure-constructor-type-mismatch.stderr +++ b/src/test/ui/structs/structure-constructor-type-mismatch.stderr @@ -74,7 +74,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/structure-constructor-type-mismatch.rs:58:15 | LL | let pt3 = PointF:: { //~ ERROR wrong number of type arguments - | ^^^^^^^^^^^^^ expected no type arguments + | ^^^^^^^^^^^^^ unexpected type argument error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:59:12 @@ -104,7 +104,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/structure-constructor-type-mismatch.rs:64:9 | LL | PointF:: { .. } => {} //~ ERROR wrong number of type arguments - | ^^^^^^^^^^^^^ expected no type arguments + | ^^^^^^^^^^^^^ unexpected type argument error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:64:9 diff --git a/src/test/ui/traits/trait-object-vs-lifetime.stderr b/src/test/ui/traits/trait-object-vs-lifetime.stderr index d875e7d48450d..ac9158dc2875f 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.stderr +++ b/src/test/ui/traits/trait-object-vs-lifetime.stderr @@ -10,11 +10,11 @@ error[E0224]: at least one non-builtin trait is required for an object type LL | let _: S<'static, 'static +>; | ^^^^^^^^^ -error[E0107]: wrong number of lifetime parameters: expected 1, found 2 +error[E0107]: wrong number of lifetime arguments: expected 1, found 2 --> $DIR/trait-object-vs-lifetime.rs:23:12 | LL | let _: S<'static, 'static>; - | ^^^^^^^^^^^^^^^^^^^ unexpected lifetime parameter + | ^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument error[E0243]: wrong number of type arguments: expected 1, found 0 --> $DIR/trait-object-vs-lifetime.rs:23:12 diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr index 58e914479637a..820c9a4d8356c 100644 --- a/src/test/ui/traits/trait-test-2.stderr +++ b/src/test/ui/traits/trait-test-2.stderr @@ -1,14 +1,14 @@ -error[E0087]: too many type parameters provided: expected at most 0 type parameters, found 1 type parameter - --> $DIR/trait-test-2.rs:18:14 +error[E0087]: wrong number of type arguments: expected 0, found 1 + --> $DIR/trait-test-2.rs:18:8 | -LL | 10.dup::(); //~ ERROR expected at most 0 type parameters, found 1 type parameter - | ^^^ expected 0 type parameters +LL | 10.dup::(); //~ ERROR wrong number of type arguments: expected 0, found 1 + | ^^^ unexpected type argument -error[E0087]: too many type parameters provided: expected at most 1 type parameter, found 2 type parameters - --> $DIR/trait-test-2.rs:19:20 +error[E0087]: wrong number of type arguments: expected 1, found 2 + --> $DIR/trait-test-2.rs:19:8 | -LL | 10.blah::(); //~ ERROR expected at most 1 type parameter, found 2 type parameters - | ^^^ expected 1 type parameter +LL | 10.blah::(); //~ ERROR wrong number of type arguments: expected 1, found 2 + | ^^^^ unexpected type argument error[E0277]: the trait bound `dyn bar: bar` is not satisfied --> $DIR/trait-test-2.rs:20:26 diff --git a/src/test/ui/ufcs/ufcs-qpath-missing-params.stderr b/src/test/ui/ufcs/ufcs-qpath-missing-params.stderr index 6c752dba6b449..2653b7bf4ac7b 100644 --- a/src/test/ui/ufcs/ufcs-qpath-missing-params.stderr +++ b/src/test/ui/ufcs/ufcs-qpath-missing-params.stderr @@ -1,8 +1,8 @@ -error[E0089]: too few type parameters provided: expected 1 type parameter, found 0 type parameters +error[E0089]: wrong number of type arguments: expected 1, found 0 --> $DIR/ufcs-qpath-missing-params.rs:24:5 | LL | ::into_cow("foo".to_string()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type parameter + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type argument error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr index 663034ba143b7..2245c5e66481e 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr @@ -1,8 +1,8 @@ -error[E0107]: wrong number of lifetime parameters: expected 1, found 0 +error[E0107]: wrong number of lifetime arguments: expected 1, found 0 --> $DIR/unboxed-closure-sugar-region.rs:40:43 | LL | fn test2(x: &Foo<(isize,),Output=()>, y: &Foo(isize)) { - | ^^^^^^^^^^ expected 1 lifetime parameter + | ^^^^^^^^^^ expected 1 lifetime argument error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr index 457bea046c762..74faa69918e46 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr @@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:15:11 | LL | fn foo(_: Zero()) - | ^^^^^^ expected no type arguments + | ^^^^^^ unexpected type argument error[E0220]: associated type `Output` not found for `Zero` --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:15:15 From ae81fc61d0ec0978a4b67a1c2627cf99f9c1d653 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Aug 2018 00:39:58 +0100 Subject: [PATCH 39/41] Fix ICE --- src/librustc_typeck/check/mod.rs | 8 ++++++-- src/test/ui/issue-53251.stderr | 15 +++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6d4d5188e3147..8703b99b9592f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4944,13 +4944,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `impl Trait` is treated as a normal generic parameter internally, // but we don't allow users to specify the parameter's value // explicitly, so we have to do some error-checking here. - suppress_errors.insert(index, AstConv::check_generic_arg_count_for_call( + let suppress = AstConv::check_generic_arg_count_for_call( self.tcx, span, &generics, &seg, false, // `is_method_call` - )); + ); + if suppress { + self.set_tainted_by_errors(); // See issue #53251. + } + suppress_errors.insert(index, suppress); } let has_self = path_segs.last().map(|PathSeg(def_id, _)| { diff --git a/src/test/ui/issue-53251.stderr b/src/test/ui/issue-53251.stderr index bf99e73f0d985..b36e9645e17bc 100644 --- a/src/test/ui/issue-53251.stderr +++ b/src/test/ui/issue-53251.stderr @@ -1,17 +1,12 @@ -error[E0601]: `main` function not found in crate `issue_53251` - | - = note: consider adding a `main` function to `$DIR/issue-53251.rs` - -error[E0087]: too many type parameters provided: expected at most 0 type parameters, found 1 type parameter - --> $DIR/issue-53251.rs:21:24 +error[E0087]: wrong number of type arguments: expected 0, found 1 + --> $DIR/issue-53251.rs:21:17 | LL | S::f::(); - | ^^^ expected 0 type parameters + | ^^^^^^^^^^^ unexpected type argument ... LL | impl_add!(a b); | --------------- in this macro invocation -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0087, E0601. -For more information about an error, try `rustc --explain E0087`. +For more information about this error, try `rustc --explain E0087`. From aa3b5c58e44beca0e96b46deb24f1bcb8d8c98a1 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Aug 2018 12:52:56 +0100 Subject: [PATCH 40/41] Fix diagnostic regression --- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_typeck/astconv.rs | 73 +++++++++---------- src/librustc_typeck/check/method/confirm.rs | 15 ++-- src/librustc_typeck/check/mod.rs | 38 +++++----- .../ui/bad/bad-mid-path-type-params.stderr | 16 ++-- src/test/ui/constructor-lifetime-args.stderr | 8 +- src/test/ui/error-codes/E0087.stderr | 8 +- src/test/ui/error-codes/E0088.stderr | 8 +- src/test/ui/error-codes/E0107.stderr | 4 +- src/test/ui/issue-53251.stderr | 4 +- src/test/ui/issues/issue-18423.stderr | 4 +- src/test/ui/issues/issue-3214.stderr | 4 +- .../method-call-lifetime-args-fail.stderr | 8 +- src/test/ui/seq-args.stderr | 8 +- ...structure-constructor-type-mismatch.stderr | 8 +- .../ui/traits/trait-object-vs-lifetime.stderr | 4 +- src/test/ui/traits/trait-test-2.stderr | 8 +- ...ypeck-builtin-bound-type-parameters.stderr | 24 +++--- .../typeck_type_placeholder_lifetime_1.stderr | 4 +- .../typeck_type_placeholder_lifetime_2.stderr | 4 +- ...wrong-number-number-type-parameters.stderr | 4 +- .../unboxed-closure-sugar-wrong-trait.stderr | 4 +- 22 files changed, 129 insertions(+), 133 deletions(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 110797a59cb7c..87504299e4bb5 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -539,7 +539,9 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) { match *generic_args { GenericArgs::AngleBracketed(ref data) => { - data.args.iter().for_each(|arg| self.visit_generic_arg(arg)); + for arg in &data.args { + self.visit_generic_arg(arg) + } for type_binding in &data.bindings { // Type bindings such as `Item=impl Debug` in `Iterator` // are allowed to contain nested `impl Trait`. diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c7926cbaa6906..ccdb751bc4eed 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -94,11 +94,12 @@ struct ConvertedBinding<'tcx> { #[derive(PartialEq)] enum GenericArgPosition { - Datatype, - Function, - Method, + Type, + Value, // e.g. functions + MethodCall, } +// FIXME(#53525): these error codes should all be unified. struct GenericArgMismatchErrorCode { lifetimes: (&'static str, &'static str), types: (&'static str, &'static str), @@ -255,9 +256,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { &empty_args }, if is_method_call { - GenericArgPosition::Method + GenericArgPosition::MethodCall } else { - GenericArgPosition::Function + GenericArgPosition::Value }, def.parent.is_none() && def.has_self, // `has_self` seg.infer_types || suppress_mismatch, // `infer_types` @@ -285,7 +286,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // arguments in order to validate them with respect to the generic parameters. let param_counts = def.own_counts(); let arg_counts = args.own_counts(); - let infer_lifetimes = position != GenericArgPosition::Datatype && arg_counts.lifetimes == 0; + let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; let mut defaults: ty::GenericParamCount = Default::default(); for param in &def.params { @@ -297,7 +298,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { }; } - if position != GenericArgPosition::Datatype && !args.bindings.is_empty() { + if position != GenericArgPosition::Type && !args.bindings.is_empty() { AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); } @@ -308,7 +309,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { if late bound lifetime parameters are present"; let note = "the late bound lifetime parameter is introduced here"; let span = args.args[0].span(); - if position == GenericArgPosition::Function + if position == GenericArgPosition::Value && arg_counts.lifetimes != param_counts.lifetimes { let mut err = tcx.sess.struct_span_err(span, msg); err.span_note(span_late, note); @@ -328,7 +329,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { kind, required, permitted, - provided| { + provided, + offset| { // We enforce the following: `required` <= `provided` <= `permitted`. // For kinds without defaults (i.e. lifetimes), `required == permitted`. // For other kinds (i.e. types), `permitted` may be greater than `required`. @@ -348,8 +350,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { (required, "") }; + let mut span = span; let label = if required == permitted && provided > permitted { let diff = provided - permitted; + if diff == 1 { + // In the case when the user has provided too many arguments, + // we want to point to the first unexpected argument. + let first_superfluous_arg: &GenericArg = &args.args[offset + permitted]; + span = first_superfluous_arg.span(); + } format!( "{}unexpected {} argument{}", if diff != 1 { format!("{} ", diff) } else { String::new() }, @@ -394,6 +403,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { param_counts.lifetimes, param_counts.lifetimes, arg_counts.lifetimes, + 0, ); } if !infer_types @@ -404,6 +414,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { param_counts.types - defaults.types - has_self as usize, param_counts.types - has_self as usize, arg_counts.types, + arg_counts.lifetimes, ) } else { false @@ -491,32 +502,27 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // provided, matching them with the generic parameters we expect. // Mismatches can occur as a result of elided lifetimes, or for malformed // input. We try to handle both sensibly. - let mut progress_arg = true; match (args.peek(), params.peek()) { (Some(&arg), Some(¶m)) => { match (arg, ¶m.kind) { - (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime) => { + (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime) + | (GenericArg::Type(_), GenericParamDefKind::Type { .. }) => { push_kind(&mut substs, provided_kind(param, arg)); + args.next(); params.next(); } (GenericArg::Lifetime(_), GenericParamDefKind::Type { .. }) => { // We expected a type argument, but got a lifetime // argument. This is an error, but we need to handle it // gracefully so we can report sensible errors. In this - // case, we're simply going to infer the remaining - // arguments. - args.by_ref().for_each(drop); // Exhaust the iterator. - } - (GenericArg::Type(_), GenericParamDefKind::Type { .. }) => { - push_kind(&mut substs, provided_kind(param, arg)); - params.next(); + // case, we're simply going to infer this argument. + args.next(); } (GenericArg::Type(_), GenericParamDefKind::Lifetime) => { // We expected a lifetime argument, but got a type // argument. That means we're inferring the lifetimes. push_kind(&mut substs, inferred_kind(None, param, infer_types)); params.next(); - progress_arg = false; } } } @@ -524,26 +530,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // We should never be able to reach this point with well-formed input. // Getting to this point means the user supplied more arguments than // there are parameters. + args.next(); } (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. match param.kind { - GenericParamDefKind::Lifetime => { - push_kind(&mut substs, inferred_kind(None, param, infer_types)); - } - GenericParamDefKind::Type { .. } => { + GenericParamDefKind::Lifetime | GenericParamDefKind::Type { .. } => { let kind = inferred_kind(Some(&substs), param, infer_types); push_kind(&mut substs, kind); } } + args.next(); params.next(); } (None, None) => break, } - if progress_arg { - args.next(); - } } } @@ -582,12 +584,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { span, &generic_params, &generic_args, - GenericArgPosition::Datatype, + GenericArgPosition::Type, has_self, infer_types, GenericArgMismatchErrorCode { lifetimes: ("E0107", "E0107"), - types: ("E0243", "E0244"), // FIXME: E0243 and E0244 should be unified. + types: ("E0243", "E0244"), }, ); @@ -616,17 +618,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { |_| (Some(generic_args), infer_types), // Provide substitutions for parameters for which (valid) arguments have been provided. |param, arg| { - match param.kind { - GenericParamDefKind::Lifetime => match arg { - GenericArg::Lifetime(lt) => { - self.ast_region_to_region(<, Some(param)).into() - } - _ => unreachable!(), + match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + self.ast_region_to_region(<, Some(param)).into() } - GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => self.ast_ty_to_ty(&ty).into(), - _ => unreachable!(), + (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + self.ast_ty_to_ty(&ty).into() } + _ => unreachable!(), } }, // Provide substitutions for parameters for which arguments are inferred. diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index e848508b8c04d..fbb49c95edf03 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -344,17 +344,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { }, // Provide substitutions for parameters for which (valid) arguments have been provided. |param, arg| { - match param.kind { - GenericParamDefKind::Lifetime => match arg { - GenericArg::Lifetime(lt) => { - AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into() - } - _ => unreachable!(), + match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into() } - GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => self.to_ty(ty).into(), - _ => unreachable!(), + (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + self.to_ty(ty).into() } + _ => unreachable!(), } }, // Provide substitutions for parameters for which arguments are inferred. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8703b99b9592f..6f0c42f48c0a7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -109,11 +109,11 @@ use session::{CompileIncomplete, config, Session}; use TypeAndSubsts; use lint; use util::common::{ErrorReported, indenter}; -use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, NodeMap}; +use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap}; use std::cell::{Cell, RefCell, Ref, RefMut}; use rustc_data_structures::sync::Lrc; -use std::collections::{hash_map::Entry, HashSet}; +use std::collections::hash_map::Entry; use std::cmp; use std::fmt::Display; use std::iter; @@ -4908,7 +4908,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // provided (if any) into their appropriate spaces. We'll also report // errors if type parameters are provided in an inappropriate place. - let mut generic_segs = HashSet::new(); + let mut generic_segs = FxHashSet::default(); for PathSeg(_, index) in &path_segs { generic_segs.insert(index); } @@ -4937,24 +4937,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // to add defaults. If the user provided *too many* types, that's // a problem. - let mut suppress_errors = FxHashMap(); + let mut infer_args_for_err = FxHashSet::default(); for &PathSeg(def_id, index) in &path_segs { let seg = &segments[index]; let generics = self.tcx.generics_of(def_id); - // `impl Trait` is treated as a normal generic parameter internally, - // but we don't allow users to specify the parameter's value - // explicitly, so we have to do some error-checking here. - let suppress = AstConv::check_generic_arg_count_for_call( + // Argument-position `impl Trait` is treated as a normal generic + // parameter internally, but we don't allow users to specify the + // parameter's value explicitly, so we have to do some error- + // checking here. + let suppress_errors = AstConv::check_generic_arg_count_for_call( self.tcx, span, &generics, &seg, false, // `is_method_call` ); - if suppress { + if suppress_errors { + infer_args_for_err.insert(index); self.set_tainted_by_errors(); // See issue #53251. } - suppress_errors.insert(index, suppress); } let has_self = path_segs.last().map(|PathSeg(def_id, _)| { @@ -4976,7 +4977,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) { // If we've encountered an `impl Trait`-related error, we're just // going to infer the arguments for better error messages. - if !suppress_errors[&index] { + if !infer_args_for_err.contains(&index) { // Check whether the user has provided generic arguments. if let Some(ref data) = segments[index].args { return (Some(data), segments[index].infer_types); @@ -4989,17 +4990,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, // Provide substitutions for parameters for which (valid) arguments have been provided. |param, arg| { - match param.kind { - GenericParamDefKind::Lifetime => match arg { - GenericArg::Lifetime(lt) => { - AstConv::ast_region_to_region(self, lt, Some(param)).into() - } - _ => unreachable!(), + match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + AstConv::ast_region_to_region(self, lt, Some(param)).into() } - GenericParamDefKind::Type { .. } => match arg { - GenericArg::Type(ty) => self.to_ty(ty).into(), - _ => unreachable!(), + (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + self.to_ty(ty).into() } + _ => unreachable!(), } }, // Provide substitutions for parameters for which arguments are inferred. diff --git a/src/test/ui/bad/bad-mid-path-type-params.stderr b/src/test/ui/bad/bad-mid-path-type-params.stderr index f0998b23c1c60..7901f1f0fba20 100644 --- a/src/test/ui/bad/bad-mid-path-type-params.stderr +++ b/src/test/ui/bad/bad-mid-path-type-params.stderr @@ -1,26 +1,26 @@ error[E0087]: wrong number of type arguments: expected 1, found 2 - --> $DIR/bad-mid-path-type-params.rs:40:13 + --> $DIR/bad-mid-path-type-params.rs:40:28 | LL | let _ = S::new::(1, 1.0); - | ^^^^^^^^^^^^^^^^^^^ unexpected type argument + | ^^^ unexpected type argument error[E0107]: wrong number of lifetime arguments: expected 0, found 1 - --> $DIR/bad-mid-path-type-params.rs:43:13 + --> $DIR/bad-mid-path-type-params.rs:43:17 | LL | let _ = S::<'a,isize>::new::(1, 1.0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument + | ^^ unexpected lifetime argument error[E0087]: wrong number of type arguments: expected 1, found 2 - --> $DIR/bad-mid-path-type-params.rs:46:17 + --> $DIR/bad-mid-path-type-params.rs:46:36 | LL | let _: S2 = Trait::new::(1, 1.0); - | ^^^^^^^^^^^^^^^^^^^^^^^ unexpected type argument + | ^^^ unexpected type argument error[E0088]: wrong number of lifetime arguments: expected 0, found 1 - --> $DIR/bad-mid-path-type-params.rs:49:17 + --> $DIR/bad-mid-path-type-params.rs:49:25 | LL | let _: S2 = Trait::<'a,isize>::new::(1, 1.0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument + | ^^ unexpected lifetime argument error: aborting due to 4 previous errors diff --git a/src/test/ui/constructor-lifetime-args.stderr b/src/test/ui/constructor-lifetime-args.stderr index 930d90c70bda5..cf3ad9ae8ecd7 100644 --- a/src/test/ui/constructor-lifetime-args.stderr +++ b/src/test/ui/constructor-lifetime-args.stderr @@ -5,10 +5,10 @@ LL | S::<'static>(&0, &0); | ^^^^^^^^^^^^ expected 2 lifetime arguments error[E0088]: wrong number of lifetime arguments: expected 2, found 3 - --> $DIR/constructor-lifetime-args.rs:29:5 + --> $DIR/constructor-lifetime-args.rs:29:27 | LL | S::<'static, 'static, 'static>(&0, &0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument + | ^^^^^^^ unexpected lifetime argument error[E0090]: wrong number of lifetime arguments: expected 2, found 1 --> $DIR/constructor-lifetime-args.rs:32:5 @@ -17,10 +17,10 @@ LL | E::V::<'static>(&0); | ^^^^^^^^^^^^^^^ expected 2 lifetime arguments error[E0088]: wrong number of lifetime arguments: expected 2, found 3 - --> $DIR/constructor-lifetime-args.rs:34:5 + --> $DIR/constructor-lifetime-args.rs:34:30 | LL | E::V::<'static, 'static, 'static>(&0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument + | ^^^^^^^ unexpected lifetime argument error: aborting due to 4 previous errors diff --git a/src/test/ui/error-codes/E0087.stderr b/src/test/ui/error-codes/E0087.stderr index 7170a6f2cda12..a07f1bbf39a3e 100644 --- a/src/test/ui/error-codes/E0087.stderr +++ b/src/test/ui/error-codes/E0087.stderr @@ -1,14 +1,14 @@ error[E0087]: wrong number of type arguments: expected 0, found 1 - --> $DIR/E0087.rs:15:5 + --> $DIR/E0087.rs:15:11 | LL | foo::(); //~ ERROR wrong number of type arguments: expected 0, found 1 [E0087] - | ^^^^^^^^^^ unexpected type argument + | ^^^ unexpected type argument error[E0087]: wrong number of type arguments: expected 1, found 2 - --> $DIR/E0087.rs:17:5 + --> $DIR/E0087.rs:17:16 | LL | bar::(); //~ ERROR wrong number of type arguments: expected 1, found 2 [E0087] - | ^^^^^^^^^^^^^^^ unexpected type argument + | ^^^ unexpected type argument error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0088.stderr b/src/test/ui/error-codes/E0088.stderr index 4666702e1ebf3..6b956023e05a4 100644 --- a/src/test/ui/error-codes/E0088.stderr +++ b/src/test/ui/error-codes/E0088.stderr @@ -1,14 +1,14 @@ error[E0088]: wrong number of lifetime arguments: expected 0, found 1 - --> $DIR/E0088.rs:15:5 + --> $DIR/E0088.rs:15:9 | LL | f::<'static>(); //~ ERROR E0088 - | ^^^^^^^^^^^^ unexpected lifetime argument + | ^^^^^^^ unexpected lifetime argument error[E0088]: wrong number of lifetime arguments: expected 1, found 2 - --> $DIR/E0088.rs:16:5 + --> $DIR/E0088.rs:16:18 | LL | g::<'static, 'static>(); //~ ERROR E0088 - | ^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument + | ^^^^^^^ unexpected lifetime argument error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0107.stderr b/src/test/ui/error-codes/E0107.stderr index 07f4f322695c3..497fa91bd4f39 100644 --- a/src/test/ui/error-codes/E0107.stderr +++ b/src/test/ui/error-codes/E0107.stderr @@ -5,10 +5,10 @@ LL | buzz: Buzz<'a>, | ^^^^^^^^ expected 2 lifetime arguments error[E0107]: wrong number of lifetime arguments: expected 0, found 1 - --> $DIR/E0107.rs:24:10 + --> $DIR/E0107.rs:24:14 | LL | bar: Bar<'a>, - | ^^^^^^^ unexpected lifetime argument + | ^^ unexpected lifetime argument error[E0107]: wrong number of lifetime arguments: expected 1, found 3 --> $DIR/E0107.rs:27:11 diff --git a/src/test/ui/issue-53251.stderr b/src/test/ui/issue-53251.stderr index b36e9645e17bc..f12afa4a79208 100644 --- a/src/test/ui/issue-53251.stderr +++ b/src/test/ui/issue-53251.stderr @@ -1,8 +1,8 @@ error[E0087]: wrong number of type arguments: expected 0, found 1 - --> $DIR/issue-53251.rs:21:17 + --> $DIR/issue-53251.rs:21:24 | LL | S::f::(); - | ^^^^^^^^^^^ unexpected type argument + | ^^^ unexpected type argument ... LL | impl_add!(a b); | --------------- in this macro invocation diff --git a/src/test/ui/issues/issue-18423.stderr b/src/test/ui/issues/issue-18423.stderr index 35063f3d3ad06..49afd51309241 100644 --- a/src/test/ui/issues/issue-18423.stderr +++ b/src/test/ui/issues/issue-18423.stderr @@ -1,8 +1,8 @@ error[E0107]: wrong number of lifetime arguments: expected 0, found 1 - --> $DIR/issue-18423.rs:14:8 + --> $DIR/issue-18423.rs:14:12 | LL | x: Box<'a, isize> //~ ERROR wrong number of lifetime arguments - | ^^^^^^^^^^^^^^ unexpected lifetime argument + | ^^ unexpected lifetime argument error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3214.stderr b/src/test/ui/issues/issue-3214.stderr index d1b846eb2aa8e..2c4b9f84105ea 100644 --- a/src/test/ui/issues/issue-3214.stderr +++ b/src/test/ui/issues/issue-3214.stderr @@ -10,10 +10,10 @@ LL | x: T, //~ ERROR can't use type parameters from outer function | ^ use of type variable from outer function error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/issue-3214.rs:16:22 + --> $DIR/issue-3214.rs:16:26 | LL | impl Drop for foo { - | ^^^^^^ unexpected type argument + | ^ unexpected type argument error: aborting due to 2 previous errors diff --git a/src/test/ui/methods/method-call-lifetime-args-fail.stderr b/src/test/ui/methods/method-call-lifetime-args-fail.stderr index 849fa574e127c..d86a9f48e003e 100644 --- a/src/test/ui/methods/method-call-lifetime-args-fail.stderr +++ b/src/test/ui/methods/method-call-lifetime-args-fail.stderr @@ -5,10 +5,10 @@ LL | S.early::<'static>(); | ^^^^^ expected 2 lifetime arguments error[E0088]: wrong number of lifetime arguments: expected 2, found 3 - --> $DIR/method-call-lifetime-args-fail.rs:28:7 + --> $DIR/method-call-lifetime-args-fail.rs:28:33 | LL | S.early::<'static, 'static, 'static>(); - | ^^^^^ unexpected lifetime argument + | ^^^^^^^ unexpected lifetime argument error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:37:15 @@ -185,10 +185,10 @@ LL | S::early::<'static>(S); | ^^^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments error[E0088]: wrong number of lifetime arguments: expected 2, found 3 - --> $DIR/method-call-lifetime-args-fail.rs:75:5 + --> $DIR/method-call-lifetime-args-fail.rs:75:34 | LL | S::early::<'static, 'static, 'static>(S); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument + | ^^^^^^^ unexpected lifetime argument error: aborting due to 18 previous errors diff --git a/src/test/ui/seq-args.stderr b/src/test/ui/seq-args.stderr index 0a68c9b917fc1..068f08eebe76c 100644 --- a/src/test/ui/seq-args.stderr +++ b/src/test/ui/seq-args.stderr @@ -1,14 +1,14 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/seq-args.rs:14:9 + --> $DIR/seq-args.rs:14:13 | LL | impl seq for Vec { //~ ERROR wrong number of type arguments - | ^^^^^^ unexpected type argument + | ^ unexpected type argument error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/seq-args.rs:17:6 + --> $DIR/seq-args.rs:17:10 | LL | impl seq for u32 { //~ ERROR wrong number of type arguments - | ^^^^^^^^^ unexpected type argument + | ^^^^ unexpected type argument error: aborting due to 2 previous errors diff --git a/src/test/ui/structs/structure-constructor-type-mismatch.stderr b/src/test/ui/structs/structure-constructor-type-mismatch.stderr index 88e3b85bca5dc..dfa219e0872ce 100644 --- a/src/test/ui/structs/structure-constructor-type-mismatch.stderr +++ b/src/test/ui/structs/structure-constructor-type-mismatch.stderr @@ -71,10 +71,10 @@ LL | x: 7, found type `{integer}` error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/structure-constructor-type-mismatch.rs:58:15 + --> $DIR/structure-constructor-type-mismatch.rs:58:24 | LL | let pt3 = PointF:: { //~ ERROR wrong number of type arguments - | ^^^^^^^^^^^^^ unexpected type argument + | ^^^ unexpected type argument error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:59:12 @@ -101,10 +101,10 @@ LL | y: 10, //~ ERROR mismatched types found type `{integer}` error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/structure-constructor-type-mismatch.rs:64:9 + --> $DIR/structure-constructor-type-mismatch.rs:64:18 | LL | PointF:: { .. } => {} //~ ERROR wrong number of type arguments - | ^^^^^^^^^^^^^ unexpected type argument + | ^^^ unexpected type argument error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:64:9 diff --git a/src/test/ui/traits/trait-object-vs-lifetime.stderr b/src/test/ui/traits/trait-object-vs-lifetime.stderr index ac9158dc2875f..c0b65a7aa5c38 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.stderr +++ b/src/test/ui/traits/trait-object-vs-lifetime.stderr @@ -11,10 +11,10 @@ LL | let _: S<'static, 'static +>; | ^^^^^^^^^ error[E0107]: wrong number of lifetime arguments: expected 1, found 2 - --> $DIR/trait-object-vs-lifetime.rs:23:12 + --> $DIR/trait-object-vs-lifetime.rs:23:23 | LL | let _: S<'static, 'static>; - | ^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument + | ^^^^^^^ unexpected lifetime argument error[E0243]: wrong number of type arguments: expected 1, found 0 --> $DIR/trait-object-vs-lifetime.rs:23:12 diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr index 820c9a4d8356c..fb9cd7019224d 100644 --- a/src/test/ui/traits/trait-test-2.stderr +++ b/src/test/ui/traits/trait-test-2.stderr @@ -1,14 +1,14 @@ error[E0087]: wrong number of type arguments: expected 0, found 1 - --> $DIR/trait-test-2.rs:18:8 + --> $DIR/trait-test-2.rs:18:14 | LL | 10.dup::(); //~ ERROR wrong number of type arguments: expected 0, found 1 - | ^^^ unexpected type argument + | ^^^ unexpected type argument error[E0087]: wrong number of type arguments: expected 1, found 2 - --> $DIR/trait-test-2.rs:19:8 + --> $DIR/trait-test-2.rs:19:20 | LL | 10.blah::(); //~ ERROR wrong number of type arguments: expected 1, found 2 - | ^^^^ unexpected type argument + | ^^^ unexpected type argument error[E0277]: the trait bound `dyn bar: bar` is not satisfied --> $DIR/trait-test-2.rs:20:26 diff --git a/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr b/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr index d34818826295f..b6444181dd8bd 100644 --- a/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr +++ b/src/test/ui/typeck/typeck-builtin-bound-type-parameters.stderr @@ -1,38 +1,38 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/typeck-builtin-bound-type-parameters.rs:11:11 + --> $DIR/typeck-builtin-bound-type-parameters.rs:11:16 | LL | fn foo1, U>(x: T) {} - | ^^^^^^^ unexpected type argument + | ^ unexpected type argument error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/typeck-builtin-bound-type-parameters.rs:14:14 + --> $DIR/typeck-builtin-bound-type-parameters.rs:14:19 | LL | trait Trait: Copy {} - | ^^^^^^^^^^ unexpected type argument + | ^^^^ unexpected type argument error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/typeck-builtin-bound-type-parameters.rs:17:21 + --> $DIR/typeck-builtin-bound-type-parameters.rs:17:26 | LL | struct MyStruct1>; - | ^^^^^^^ unexpected type argument + | ^ unexpected type argument error[E0107]: wrong number of lifetime arguments: expected 0, found 1 - --> $DIR/typeck-builtin-bound-type-parameters.rs:20:25 + --> $DIR/typeck-builtin-bound-type-parameters.rs:20:30 | LL | struct MyStruct2<'a, T: Copy<'a>>; - | ^^^^^^^^ unexpected lifetime argument + | ^^ unexpected lifetime argument error[E0107]: wrong number of lifetime arguments: expected 0, found 1 - --> $DIR/typeck-builtin-bound-type-parameters.rs:24:15 + --> $DIR/typeck-builtin-bound-type-parameters.rs:24:20 | LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} - | ^^^^^^^^^^^ unexpected lifetime argument + | ^^ unexpected lifetime argument error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/typeck-builtin-bound-type-parameters.rs:24:15 + --> $DIR/typeck-builtin-bound-type-parameters.rs:24:24 | LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} - | ^^^^^^^^^^^ unexpected type argument + | ^ unexpected type argument error: aborting due to 6 previous errors diff --git a/src/test/ui/typeck/typeck_type_placeholder_lifetime_1.stderr b/src/test/ui/typeck/typeck_type_placeholder_lifetime_1.stderr index 597fbc6d8b1bc..a49839b731070 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_lifetime_1.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_lifetime_1.stderr @@ -1,8 +1,8 @@ error[E0244]: wrong number of type arguments: expected 1, found 2 - --> $DIR/typeck_type_placeholder_lifetime_1.rs:19:12 + --> $DIR/typeck_type_placeholder_lifetime_1.rs:19:19 | LL | let c: Foo<_, _> = Foo { r: &5 }; - | ^^^^^^^^^ unexpected type argument + | ^ unexpected type argument error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck_type_placeholder_lifetime_2.stderr b/src/test/ui/typeck/typeck_type_placeholder_lifetime_2.stderr index 1b7c60441e16b..cafb6f507a0e9 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_lifetime_2.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_lifetime_2.stderr @@ -1,8 +1,8 @@ error[E0244]: wrong number of type arguments: expected 1, found 2 - --> $DIR/typeck_type_placeholder_lifetime_2.rs:19:12 + --> $DIR/typeck_type_placeholder_lifetime_2.rs:19:19 | LL | let c: Foo<_, usize> = Foo { r: &5 }; - | ^^^^^^^^^^^^^ unexpected type argument + | ^^^^^ unexpected type argument error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr index 74faa69918e46..89587c47cf67d 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr @@ -1,8 +1,8 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:15:11 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:15:15 | LL | fn foo(_: Zero()) - | ^^^^^^ unexpected type argument + | ^^ unexpected type argument error[E0220]: associated type `Output` not found for `Zero` --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:15:15 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr index a993928bc318a..5d8c86f5a5809 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr @@ -1,8 +1,8 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 - --> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:8 + --> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:13 | LL | fn f isize>(x: F) {} - | ^^^^^^^^^^^^^^^^^^^^^ unexpected type argument + | ^^^^^^^^^^^^^^^^ unexpected type argument error[E0220]: associated type `Output` not found for `Trait` --> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:24 From ee9bd0fd99ef5049f53b5d8233369187637cb71c Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Aug 2018 16:32:59 +0100 Subject: [PATCH 41/41] Add a test for skipping all arguments versus just one --- .../generic/generic-arg-mismatch-recover.rs | 21 +++++++++++++ .../generic-arg-mismatch-recover.stderr | 31 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/test/ui/generic/generic-arg-mismatch-recover.rs create mode 100644 src/test/ui/generic/generic-arg-mismatch-recover.stderr diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.rs b/src/test/ui/generic/generic-arg-mismatch-recover.rs new file mode 100644 index 0000000000000..b8883ff9c8333 --- /dev/null +++ b/src/test/ui/generic/generic-arg-mismatch-recover.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo<'a, T: 'a>(&'a T); + +struct Bar<'a>(&'a ()); + +fn main() { + Foo::<'static, 'static, ()>(&0); //~ ERROR wrong number of lifetime arguments + //~^ ERROR mismatched types + + Bar::<'static, 'static, ()>(&()); //~ ERROR wrong number of lifetime arguments + //~^ ERROR wrong number of type arguments +} diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.stderr b/src/test/ui/generic/generic-arg-mismatch-recover.stderr new file mode 100644 index 0000000000000..81869ad0d08a5 --- /dev/null +++ b/src/test/ui/generic/generic-arg-mismatch-recover.stderr @@ -0,0 +1,31 @@ +error[E0088]: wrong number of lifetime arguments: expected 1, found 2 + --> $DIR/generic-arg-mismatch-recover.rs:16:20 + | +LL | Foo::<'static, 'static, ()>(&0); //~ ERROR wrong number of lifetime arguments + | ^^^^^^^ unexpected lifetime argument + +error[E0308]: mismatched types + --> $DIR/generic-arg-mismatch-recover.rs:16:33 + | +LL | Foo::<'static, 'static, ()>(&0); //~ ERROR wrong number of lifetime arguments + | ^^ expected (), found integral variable + | + = note: expected type `&'static ()` + found type `&{integer}` + +error[E0088]: wrong number of lifetime arguments: expected 1, found 2 + --> $DIR/generic-arg-mismatch-recover.rs:19:20 + | +LL | Bar::<'static, 'static, ()>(&()); //~ ERROR wrong number of lifetime arguments + | ^^^^^^^ unexpected lifetime argument + +error[E0087]: wrong number of type arguments: expected 0, found 1 + --> $DIR/generic-arg-mismatch-recover.rs:19:29 + | +LL | Bar::<'static, 'static, ()>(&()); //~ ERROR wrong number of lifetime arguments + | ^^ unexpected type argument + +error: aborting due to 4 previous errors + +Some errors occurred: E0087, E0088, E0308. +For more information about an error, try `rustc --explain E0087`.