Skip to content

Commit d1a82af

Browse files
committed
Refactor mod/check (part i)
1 parent 2317abd commit d1a82af

File tree

2 files changed

+166
-102
lines changed

2 files changed

+166
-102
lines changed

src/librustc_typeck/check/method/confirm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
315315
// If they were not explicitly supplied, just construct fresh
316316
// variables.
317317
let method_generics = self.tcx.generics_of(pick.item.def_id);
318-
let mut fn_segment = Some((segment, method_generics));
318+
let fn_segment = Some((segment, method_generics));
319319
let supress_mismatch = self.fcx.check_impl_trait(self.span, fn_segment);
320-
self.fcx.check_generic_arg_count(self.span, &mut fn_segment, true, supress_mismatch);
320+
self.fcx.check_generic_arg_count(self.span, &segment, &method_generics, true, supress_mismatch);
321321

322322
// Create subst for early-bound lifetime parameters, combining
323323
// parameters from the type and those from the method.

src/librustc_typeck/check/mod.rs

Lines changed: 164 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, NodeMap};
113113

114114
use std::cell::{Cell, RefCell, Ref, RefMut};
115115
use rustc_data_structures::sync::Lrc;
116-
use std::collections::hash_map::Entry;
116+
use std::collections::{hash_map::Entry, HashSet};
117117
use std::cmp;
118118
use std::fmt::Display;
119119
use std::iter;
@@ -505,6 +505,9 @@ impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> {
505505
}
506506
}
507507

508+
#[derive(Debug)]
509+
struct PathSeg(DefId, usize);
510+
508511
pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
509512
body_id: ast::NodeId,
510513

@@ -4770,20 +4773,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
47704773
err.span_suggestion(span_semi, "consider removing this semicolon", "".to_string());
47714774
}
47724775

4773-
// Instantiates the given path, which must refer to an item with the given
4774-
// number of type parameters and type.
4775-
pub fn instantiate_value_path(&self,
4776-
segments: &[hir::PathSegment],
4777-
opt_self_ty: Option<Ty<'tcx>>,
4778-
def: Def,
4779-
span: Span,
4780-
node_id: ast::NodeId)
4781-
-> Ty<'tcx> {
4782-
debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})",
4783-
segments,
4784-
def,
4785-
node_id);
4786-
4776+
fn def_ids_for_path_segments(&self,
4777+
segments: &[hir::PathSegment],
4778+
def: Def)
4779+
-> Vec<PathSeg> {
47874780
// We need to extract the type parameters supplied by the user in
47884781
// the path `path`. Due to the current setup, this is a bit of a
47894782
// tricky-process; the problem is that resolve only tells us the
@@ -4829,33 +4822,69 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
48294822
// The first step then is to categorize the segments appropriately.
48304823

48314824
assert!(!segments.is_empty());
4825+
let last = segments.len() - 1;
4826+
4827+
let mut path_segs = vec![];
48324828

4833-
let mut ufcs_associated = None;
4834-
let mut type_segment = None;
4835-
let mut fn_segment = None;
48364829
match def {
48374830
// Case 1. Reference to a struct/variant constructor.
48384831
Def::StructCtor(def_id, ..) |
48394832
Def::VariantCtor(def_id, ..) => {
48404833
// Everything but the final segment should have no
48414834
// parameters at all.
48424835
let mut generics = self.tcx.generics_of(def_id);
4843-
if let Some(def_id) = generics.parent {
4844-
// Variant and struct constructors use the
4845-
// generics of their parent type definition.
4846-
generics = self.tcx.generics_of(def_id);
4847-
}
4848-
type_segment = Some((segments.last().unwrap(), generics));
4836+
// Variant and struct constructors use the
4837+
// generics of their parent type definition.
4838+
let generics_def_id = generics.parent.unwrap_or(def_id);
4839+
path_segs.push(PathSeg(generics_def_id, last));
48494840
}
48504841

48514842
// Case 2. Reference to a top-level value.
48524843
Def::Fn(def_id) |
48534844
Def::Const(def_id) |
48544845
Def::Static(def_id, _) => {
4855-
fn_segment = Some((segments.last().unwrap(), self.tcx.generics_of(def_id)));
4846+
path_segs.push(PathSeg(def_id, last));
48564847
}
48574848

48584849
// Case 3. Reference to a method or associated const.
4850+
Def::Method(def_id) |
4851+
Def::AssociatedConst(def_id) => {
4852+
if segments.len() >= 2 {
4853+
let generics = self.tcx.generics_of(def_id);
4854+
path_segs.push(PathSeg(generics.parent.unwrap(), last - 1));
4855+
}
4856+
path_segs.push(PathSeg(def_id, last));
4857+
}
4858+
4859+
// Case 4. Local variable, no generics.
4860+
Def::Local(..) | Def::Upvar(..) => {}
4861+
4862+
_ => bug!("unexpected definition: {:?}", def),
4863+
}
4864+
4865+
debug!("path_segs = {:?}", path_segs);
4866+
4867+
path_segs
4868+
}
4869+
4870+
// Instantiates the given path, which must refer to an item with the given
4871+
// number of type parameters and type.
4872+
pub fn instantiate_value_path(&self,
4873+
segments: &[hir::PathSegment],
4874+
opt_self_ty: Option<Ty<'tcx>>,
4875+
def: Def,
4876+
span: Span,
4877+
node_id: ast::NodeId)
4878+
-> Ty<'tcx> {
4879+
debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})",
4880+
segments,
4881+
def,
4882+
node_id);
4883+
4884+
let path_segs = self.def_ids_for_path_segments(segments, def);
4885+
4886+
let mut ufcs_associated = None;
4887+
match def {
48594888
Def::Method(def_id) |
48604889
Def::AssociatedConst(def_id) => {
48614890
let container = self.tcx.associated_item(def_id).container;
@@ -4865,34 +4894,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
48654894
}
48664895
ty::ImplContainer(_) => {}
48674896
}
4868-
4869-
let generics = self.tcx.generics_of(def_id);
4870-
if segments.len() >= 2 {
4871-
let parent_generics = self.tcx.generics_of(generics.parent.unwrap());
4872-
type_segment = Some((&segments[segments.len() - 2], parent_generics));
4873-
} else {
4897+
if segments.len() == 1 {
48744898
// `<T>::assoc` will end up here, and so can `T::assoc`.
48754899
let self_ty = opt_self_ty.expect("UFCS sugared assoc missing Self");
48764900
ufcs_associated = Some((container, self_ty));
48774901
}
4878-
fn_segment = Some((segments.last().unwrap(), generics));
48794902
}
4880-
4881-
// Case 4. Local variable, no generics.
4882-
Def::Local(..) | Def::Upvar(..) => {}
4883-
4884-
_ => bug!("unexpected definition: {:?}", def),
4903+
_ => {}
48854904
}
48864905

4887-
debug!("type_segment={:?} fn_segment={:?}", type_segment, fn_segment);
4888-
48894906
// Now that we have categorized what space the parameters for each
48904907
// segment belong to, let's sort out the parameters that the user
48914908
// provided (if any) into their appropriate spaces. We'll also report
48924909
// errors if type parameters are provided in an inappropriate place.
4893-
let poly_segments = type_segment.is_some() as usize +
4894-
fn_segment.is_some() as usize;
4895-
AstConv::prohibit_generics(self, &segments[..segments.len() - poly_segments]);
4910+
let mut generic_segs = HashSet::new();
4911+
for PathSeg(_, index) in &path_segs {
4912+
generic_segs.insert(index);
4913+
}
4914+
let segs: Vec<_> = segments
4915+
.iter()
4916+
.enumerate()
4917+
.filter_map(|(index, seg)| {
4918+
if !generic_segs.contains(&index) {
4919+
Some(seg)
4920+
} else {
4921+
None
4922+
}
4923+
})
4924+
.cloned()
4925+
.collect();
4926+
AstConv::prohibit_generics(self, &segs);
48964927

48974928
match def {
48984929
Def::Local(nid) | Def::Upvar(nid, ..) => {
@@ -4904,24 +4935,66 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
49044935
_ => {}
49054936
}
49064937

4938+
let mut type_segment = None;
4939+
let mut fn_segment = None;
4940+
match def {
4941+
// Case 1. Reference to a struct/variant constructor.
4942+
Def::StructCtor(def_id, ..) |
4943+
Def::VariantCtor(def_id, ..) => {
4944+
// Everything but the final segment should have no
4945+
// parameters at all.
4946+
let mut generics = self.tcx.generics_of(def_id);
4947+
if let Some(def_id) = generics.parent {
4948+
// Variant and struct constructors use the
4949+
// generics of their parent type definition.
4950+
generics = self.tcx.generics_of(def_id);
4951+
}
4952+
type_segment = Some((segments.last().unwrap(), generics));
4953+
}
4954+
4955+
// Case 2. Reference to a top-level value.
4956+
Def::Fn(def_id) |
4957+
Def::Const(def_id) |
4958+
Def::Static(def_id, _) => {
4959+
fn_segment = Some((segments.last().unwrap(), self.tcx.generics_of(def_id)));
4960+
}
4961+
4962+
// Case 3. Reference to a method or associated const.
4963+
Def::Method(def_id) |
4964+
Def::AssociatedConst(def_id) => {
4965+
let generics = self.tcx.generics_of(def_id);
4966+
if segments.len() >= 2 {
4967+
let parent_generics = self.tcx.generics_of(generics.parent.unwrap());
4968+
type_segment = Some((&segments[segments.len() - 2], parent_generics));
4969+
}
4970+
fn_segment = Some((segments.last().unwrap(), generics));
4971+
}
4972+
4973+
_ => {}
4974+
}
4975+
4976+
debug!("type_segment={:?} fn_segment={:?}", type_segment, fn_segment);
4977+
49074978
// Now we have to compare the types that the user *actually*
49084979
// provided against the types that were *expected*. If the user
49094980
// did not provide any types, then we want to substitute inference
49104981
// variables. If the user provided some types, we may still need
49114982
// to add defaults. If the user provided *too many* types, that's
49124983
// a problem.
49134984
let supress_mismatch = self.check_impl_trait(span, fn_segment);
4914-
self.check_generic_arg_count(span, &mut type_segment, false, supress_mismatch);
4915-
self.check_generic_arg_count(span, &mut fn_segment, false, supress_mismatch);
4985+
for &PathSeg(def_id, index) in &path_segs {
4986+
let generics = self.tcx.generics_of(def_id);
4987+
self.check_generic_arg_count(span, &segments[index], &generics, false, supress_mismatch);
4988+
}
49164989

4917-
let (fn_start, has_self) = match (type_segment, fn_segment) {
4918-
(_, Some((_, generics))) => {
4919-
(generics.parent_count, generics.has_self)
4920-
}
4921-
(Some((_, generics)), None) => {
4922-
(generics.params.len(), generics.has_self)
4923-
}
4924-
(None, None) => (0, false)
4990+
let has_self = path_segs.last().map(|PathSeg(def_id, _)| {
4991+
self.tcx.generics_of(*def_id).has_self
4992+
}).unwrap_or(false);
4993+
4994+
let fn_start = match (type_segment, fn_segment) {
4995+
(_, Some((_, generics))) => generics.parent_count,
4996+
(Some((_, generics)), None) => generics.params.len(),
4997+
(None, None) => 0,
49254998
};
49264999
// FIXME(varkor): Separating out the parameters is messy.
49275000
let mut lifetimes_type_seg = vec![];
@@ -5091,64 +5164,55 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
50915164
/// Report errors if the provided parameters are too few or too many.
50925165
fn check_generic_arg_count(&self,
50935166
span: Span,
5094-
segment: &mut Option<(&hir::PathSegment, &ty::Generics)>,
5167+
segment: &hir::PathSegment,
5168+
generics: &ty::Generics,
50955169
is_method_call: bool,
50965170
supress_mismatch_error: bool) {
5097-
let (lifetimes, types, infer_types, bindings) = segment.map_or(
5098-
(vec![], vec![], true, &[][..]),
5099-
|(s, _)| {
5100-
s.args.as_ref().map_or(
5101-
(vec![], vec![], s.infer_types, &[][..]),
5102-
|data| {
5103-
let (mut lifetimes, mut types) = (vec![], vec![]);
5104-
data.args.iter().for_each(|arg| match arg {
5105-
GenericArg::Lifetime(lt) => lifetimes.push(lt),
5106-
GenericArg::Type(ty) => types.push(ty),
5107-
});
5108-
(lifetimes, types, s.infer_types, &data.bindings[..])
5109-
}
5110-
)
5171+
let (mut lifetimes, mut types) = (vec![], vec![]);
5172+
let infer_types = segment.infer_types;
5173+
let mut bindings = vec![];
5174+
if let Some(ref data) = segment.args {
5175+
data.args.iter().for_each(|arg| match arg {
5176+
GenericArg::Lifetime(lt) => lifetimes.push(lt.clone()),
5177+
GenericArg::Type(ty) => types.push(ty.clone()),
51115178
});
5179+
bindings = data.bindings.clone().to_vec();
5180+
}
51125181

5113-
// Check provided parameters.
5114-
let ((ty_required, ty_accepted), lt_accepted) =
5115-
segment.map_or(((0, 0), 0), |(_, generics)| {
5116-
struct ParamRange {
5117-
required: usize,
5118-
accepted: usize
5119-
};
5182+
struct ParamRange {
5183+
required: usize,
5184+
accepted: usize
5185+
};
51205186

5121-
let mut lt_accepted = 0;
5122-
let mut ty_params = ParamRange { required: 0, accepted: 0 };
5123-
for param in &generics.params {
5124-
match param.kind {
5125-
GenericParamDefKind::Lifetime => lt_accepted += 1,
5126-
GenericParamDefKind::Type { has_default, .. } => {
5127-
ty_params.accepted += 1;
5128-
if !has_default {
5129-
ty_params.required += 1;
5130-
}
5131-
}
5132-
};
5133-
}
5134-
if generics.parent.is_none() && generics.has_self {
5135-
ty_params.required -= 1;
5136-
ty_params.accepted -= 1;
5187+
let mut lt_accepted = 0;
5188+
let mut ty_params = ParamRange { required: 0, accepted: 0 };
5189+
for param in &generics.params {
5190+
match param.kind {
5191+
GenericParamDefKind::Lifetime => lt_accepted += 1,
5192+
GenericParamDefKind::Type { has_default, .. } => {
5193+
ty_params.accepted += 1;
5194+
if !has_default {
5195+
ty_params.required += 1;
5196+
}
51375197
}
5198+
};
5199+
}
5200+
if generics.parent.is_none() && generics.has_self {
5201+
ty_params.required -= 1;
5202+
ty_params.accepted -= 1;
5203+
}
5204+
let ty_accepted = ty_params.accepted;
5205+
let ty_required = ty_params.required;
51385206

5139-
((ty_params.required, ty_params.accepted), lt_accepted)
5140-
});
5141-
5142-
let count_type_params = |n| {
5143-
format!("{} type parameter{}", n, if n == 1 { "" } else { "s" })
5144-
};
5207+
let count_type_params = |n| format!("{} type parameter{}", n, if n == 1 { "" } else { "s" });
51455208
let expected_text = count_type_params(ty_accepted);
51465209
let actual_text = count_type_params(types.len());
51475210
if let Some((mut err, span)) = if types.len() > ty_accepted {
51485211
// To prevent derived errors to accumulate due to extra
51495212
// type parameters, we force instantiate_value_path to
51505213
// use inference variables instead of the provided types.
5151-
*segment = None;
5214+
// FIXME(varkor)
5215+
// *segment = None;
51525216
let span = types[ty_accepted].span;
51535217
Some((struct_span_err!(self.tcx.sess, span, E0087,
51545218
"too many type parameters provided: \
@@ -5172,8 +5236,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
51725236

51735237
let infer_lifetimes = lifetimes.len() == 0;
51745238
// Prohibit explicit lifetime arguments if late bound lifetime parameters are present.
5175-
let has_late_bound_lifetime_defs =
5176-
segment.map_or(None, |(_, generics)| generics.has_late_bound_regions);
5239+
let has_late_bound_lifetime_defs = generics.has_late_bound_regions;
51775240
if let (Some(span_late), false) = (has_late_bound_lifetime_defs, lifetimes.is_empty()) {
51785241
// Report this as a lint only if no error was reported previously.
51795242
let primary_msg = "cannot specify lifetime arguments explicitly \
@@ -5184,7 +5247,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
51845247
let mut err = self.tcx.sess.struct_span_err(lifetimes[0].span, primary_msg);
51855248
err.span_note(span_late, note_msg);
51865249
err.emit();
5187-
*segment = None;
5250+
// FIXME(varkor)
5251+
// *segment = None;
51885252
} else {
51895253
let mut multispan = MultiSpan::from_span(lifetimes[0].span);
51905254
multispan.push_span_label(span_late, note_msg.to_string());

0 commit comments

Comments
 (0)