Skip to content

Commit 9967e9e

Browse files
committed
Support generic lifetime arguments in method calls
1 parent 028569a commit 9967e9e

File tree

8 files changed

+53
-172
lines changed

8 files changed

+53
-172
lines changed

src/librustc_passes/ast_validation.rs

+3-12
Original file line numberDiff line numberDiff line change
@@ -127,18 +127,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
127127
}
128128
ExprKind::MethodCall(ref segment, ..) => {
129129
if let Some(ref params) = segment.parameters {
130-
match **params {
131-
PathParameters::AngleBracketed(ref param_data) => {
132-
if !param_data.bindings.is_empty() {
133-
let binding_span = param_data.bindings[0].span;
134-
self.err_handler().span_err(binding_span,
135-
"type bindings cannot be used in method calls");
136-
}
137-
}
138-
PathParameters::Parenthesized(..) => {
139-
self.err_handler().span_err(expr.span,
140-
"parenthesized parameters cannot be used on method calls");
141-
}
130+
if let PathParameters::Parenthesized(..) = **params {
131+
self.err_handler().span_err(expr.span,
132+
"parenthesized parameters cannot be used on method calls");
142133
}
143134
}
144135
}

src/librustc_typeck/check/method/confirm.rs

+10-36
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use super::{probe, MethodCallee};
1212

13+
use astconv::AstConv;
1314
use check::{FnCtxt, LvalueOp, callee};
1415
use hir::def_id::DefId;
1516
use rustc::ty::subst::Substs;
@@ -282,60 +283,33 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
282283
segment: &hir::PathSegment,
283284
substs: &Substs<'tcx>)
284285
-> &'tcx Substs<'tcx> {
285-
let supplied_method_types = match segment.parameters {
286-
hir::AngleBracketedParameters(ref data) => &data.types,
287-
_ => bug!("unexpected generic arguments: {:?}", segment.parameters),
288-
};
289-
290286
// Determine the values for the generic parameters of the method.
291287
// If they were not explicitly supplied, just construct fresh
292288
// variables.
293-
let num_supplied_types = supplied_method_types.len();
294289
let method_generics = self.tcx.generics_of(pick.item.def_id);
295-
let num_method_types = method_generics.types.len();
296-
297-
if num_supplied_types > 0 && num_supplied_types != num_method_types {
298-
if num_method_types == 0 {
299-
struct_span_err!(self.tcx.sess,
300-
self.span,
301-
E0035,
302-
"does not take type parameters")
303-
.span_label(self.span, "called with unneeded type parameters")
304-
.emit();
305-
} else {
306-
struct_span_err!(self.tcx.sess,
307-
self.span,
308-
E0036,
309-
"incorrect number of type parameters given for this method: \
310-
expected {}, found {}",
311-
num_method_types,
312-
num_supplied_types)
313-
.span_label(self.span,
314-
format!("Passed {} type argument{}, expected {}",
315-
num_supplied_types,
316-
if num_supplied_types != 1 { "s" } else { "" },
317-
num_method_types))
318-
.emit();
319-
}
320-
}
290+
let mut fn_segment = Some((segment, method_generics));
291+
self.fcx.check_path_parameter_count(self.span, &mut fn_segment);
321292

322293
// Create subst for early-bound lifetime parameters, combining
323294
// parameters from the type and those from the method.
324-
//
325-
// FIXME -- permit users to manually specify lifetimes
326-
let supplied_start = substs.len() + method_generics.regions.len();
295+
let (supplied_types, supplied_lifetimes) = match segment.parameters {
296+
hir::AngleBracketedParameters(ref data) => (&data.types, &data.lifetimes),
297+
_ => bug!("unexpected generic arguments: {:?}", segment.parameters),
298+
};
327299
Substs::for_item(self.tcx, pick.item.def_id, |def, _| {
328300
let i = def.index as usize;
329301
if i < substs.len() {
330302
substs.region_at(i)
303+
} else if let Some(lifetime) = supplied_lifetimes.get(i - substs.len()) {
304+
AstConv::ast_region_to_region(self.fcx, lifetime, Some(def))
331305
} else {
332306
self.region_var_for_def(self.span, def)
333307
}
334308
}, |def, cur_substs| {
335309
let i = def.index as usize;
336310
if i < substs.len() {
337311
substs.type_at(i)
338-
} else if let Some(ast_ty) = supplied_method_types.get(i - supplied_start) {
312+
} else if let Some(ast_ty) = supplied_types.get(i - substs.len()) {
339313
self.to_ty(ast_ty)
340314
} else {
341315
self.type_var_for_def(self.span, def, cur_substs)

src/librustc_typeck/diagnostics.rs

+2-86
Original file line numberDiff line numberDiff line change
@@ -332,92 +332,6 @@ fn main() {
332332
```
333333
"##,
334334

335-
E0035: r##"
336-
You tried to give a type parameter where it wasn't needed. Erroneous code
337-
example:
338-
339-
```compile_fail,E0035
340-
struct Test;
341-
342-
impl Test {
343-
fn method(&self) {}
344-
}
345-
346-
fn main() {
347-
let x = Test;
348-
349-
x.method::<i32>(); // Error: Test::method doesn't need type parameter!
350-
}
351-
```
352-
353-
To fix this error, just remove the type parameter:
354-
355-
```
356-
struct Test;
357-
358-
impl Test {
359-
fn method(&self) {}
360-
}
361-
362-
fn main() {
363-
let x = Test;
364-
365-
x.method(); // OK, we're good!
366-
}
367-
```
368-
"##,
369-
370-
E0036: r##"
371-
This error occurrs when you pass too many or not enough type parameters to
372-
a method. Erroneous code example:
373-
374-
```compile_fail,E0036
375-
struct Test;
376-
377-
impl Test {
378-
fn method<T>(&self, v: &[T]) -> usize {
379-
v.len()
380-
}
381-
}
382-
383-
fn main() {
384-
let x = Test;
385-
let v = &[0];
386-
387-
x.method::<i32, i32>(v); // error: only one type parameter is expected!
388-
}
389-
```
390-
391-
To fix it, just specify a correct number of type parameters:
392-
393-
```
394-
struct Test;
395-
396-
impl Test {
397-
fn method<T>(&self, v: &[T]) -> usize {
398-
v.len()
399-
}
400-
}
401-
402-
fn main() {
403-
let x = Test;
404-
let v = &[0];
405-
406-
x.method::<i32>(v); // OK, we're good!
407-
}
408-
```
409-
410-
Please note on the last example that we could have called `method` like this:
411-
412-
```
413-
# struct Test;
414-
# impl Test { fn method<T>(&self, v: &[T]) -> usize { v.len() } }
415-
# let x = Test;
416-
# let v = &[0];
417-
x.method(v);
418-
```
419-
"##,
420-
421335
E0040: r##"
422336
It is not allowed to manually call destructors in Rust. It is also not
423337
necessary to do this since `drop` is called automatically whenever a value goes
@@ -4681,6 +4595,8 @@ error, just declare a function.
46814595
}
46824596

46834597
register_diagnostics! {
4598+
// E0035, merged into E0087/E0089
4599+
// E0036, merged into E0087/E0089
46844600
// E0068,
46854601
// E0085,
46864602
// E0086,

src/test/compile-fail/E0036.rs

-24
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -8,14 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
struct Test;
12-
13-
impl Test {
14-
fn method(&self) {}
15-
}
16-
1711
fn main() {
18-
let x = Test;
19-
x.method::<i32>(); //~ ERROR E0035
20-
//~| NOTE called with unneeded type parameters
12+
0.clone::<'a>(); //~ ERROR use of undeclared lifetime name `'a`
2113
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct S;
12+
13+
impl S {
14+
fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
15+
fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
16+
fn life_and_type<'a, T>(&self) -> &'a T { loop {} }
17+
}
18+
19+
fn main() {
20+
S.late(&0, &0); // OK
21+
S.late::<'static>(&0, &0);
22+
//~^ ERROR expected at most 0 lifetime parameters, found 1 lifetime parameter
23+
S.late::<'static, 'static, 'static>(&0, &0);
24+
//~^ ERROR expected at most 0 lifetime parameters, found 3 lifetime parameter
25+
S.early(); // OK
26+
S.early::<'static>();
27+
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
28+
S.early::<'static, 'static, 'static>();
29+
//~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
30+
let _: &u8 = S.life_and_type::<'static>();
31+
S.life_and_type::<u8>();
32+
S.life_and_type::<'static, u8>();
33+
}

src/test/compile-fail/method-call-type-binding.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
// except according to those terms.
1010

1111
fn main() {
12-
0.clone::<T = u8>(); //~ ERROR type bindings cannot be used in method calls
12+
0.clone::<T = u8>(); //~ ERROR unexpected binding of associated item
1313
}

src/test/compile-fail/trait-test-2.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
1515
impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
1616

1717
fn main() {
18-
10.dup::<i32>(); //~ ERROR does not take type parameters
19-
10.blah::<i32, i32>();
20-
//~^ ERROR incorrect number of type parameters given for this method: expected 1, found 2
18+
10.dup::<i32>(); //~ ERROR expected at most 0 type parameters, found 1 type parameter
19+
10.blah::<i32, i32>(); //~ ERROR expected at most 1 type parameter, found 2 type parameters
2120
(box 10 as Box<bar>).dup();
2221
//~^ ERROR E0038
2322
//~| ERROR E0038

0 commit comments

Comments
 (0)