Skip to content

Commit 2585803

Browse files
committed
auto merge of #12764 : Kimundi/rust/partial_typehint, r=nikomatsakis
# Summary This patch introduces the `_` token into the type grammar, with the meaning "infer this type". With this change, the following two lines become equivalent: ``` let x = foo(); let x: _ = foo(); ``` But due to its composability, it enables partial type hints like this: ``` let x: Bar<_> = baz(); ``` Using it on the item level is explicitly forbidden, as the Rust language does not enable global type inference by design. This implements the feature requested in #9508. # Things requiring clarification - The change to enable it is very small, but I have only limited understanding of the related code, so the approach here might be wrong. - In particular, while this patch works, it does so in a way not originally intended according to the code comments. - This probably needs more tests, or rather feedback for which tests are still missing. - I'm unsure how this interacts with lifetime parameters, and whether it is correct in regard to them. - Partial type hints on the right side of `as` like `&foo as *_` work in both a normal function contexts and in constexprs like `static foo: *int = &'static 123 as *_`. The question is whether this should be allowed in general. # Todo for this PR - The manual and tutorial still needs updating. # Bugs I'm unsure how to fix - Requesting inference for the top level of the right hand side of a `as` fails to infer correctly, even if all possible hints are given: ``` .../type_hole_1.rs:35:18: 35:22 error: the type of this value must be known in this context .../type_hole_1.rs:35 let a: int = 1u32 as _; ^~~~ ```
2 parents 339f816 + eb69eb3 commit 2585803

10 files changed

+236
-11
lines changed

src/librustc/middle/typeck/astconv.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -640,13 +640,11 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
640640
tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
641641
}
642642
ast::TyInfer => {
643-
// ty_infer should only appear as the type of arguments or return
644-
// values in a fn_expr, or as the type of local variables. Both of
645-
// these cases are handled specially and should not descend into this
646-
// routine.
647-
this.tcx().sess.span_bug(
648-
ast_ty.span,
649-
"found `ty_infer` in unexpected place");
643+
// TyInfer also appears as the type of arguments or return
644+
// values in a ExprFnBlock or ExprProc, or as the type of
645+
// local variables. Both of these cases are handled specially
646+
// and will not descend into this routine.
647+
this.ty_infer(ast_ty.span)
650648
}
651649
});
652650

src/librustc/middle/typeck/collect.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ impl AstConv for CrateCtxt {
132132
}
133133

134134
fn ty_infer(&self, span: Span) -> ty::t {
135-
self.tcx.sess.span_bug(span, "found `ty_infer` in unexpected place");
135+
self.tcx.sess.span_err(span, "the type placeholder `_` is not \
136+
allowed within types on item signatures.");
137+
ty::mk_err()
136138
}
137139
}
138140

src/libsyntax/ast.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -830,8 +830,7 @@ pub enum Ty_ {
830830
TyPath(Path, Option<OptVec<TyParamBound>>, NodeId), // for #7264; see above
831831
TyTypeof(@Expr),
832832
// TyInfer means the type should be inferred instead of it having been
833-
// specified. This should only appear at the "top level" of a type and not
834-
// nested in one.
833+
// specified. This can appear anywhere in a type.
835834
TyInfer,
836835
}
837836

src/libsyntax/parse/parser.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,9 @@ impl Parser {
12741274
bounds
12751275
} = self.parse_path(LifetimeAndTypesAndBounds);
12761276
TyPath(path, bounds, ast::DUMMY_NODE_ID)
1277+
} else if self.eat(&token::UNDERSCORE) {
1278+
// TYPE TO BE INFERRED
1279+
TyInfer
12771280
} else {
12781281
let msg = format!("expected type, found token {:?}", self.token);
12791282
self.fatal(msg);

src/libsyntax/print/pprust.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ pub fn print_type(s: &mut State, ty: &ast::Ty) -> io::IoResult<()> {
504504
try!(word(&mut s.s, ")"));
505505
}
506506
ast::TyInfer => {
507-
fail!("print_type shouldn't see a ty_infer");
507+
try!(word(&mut s.s, "_"));
508508
}
509509
}
510510
end(s)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2014 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+
// This test checks that it is not possible to enable global type
12+
// inference by using the `_` type placeholder.
13+
14+
fn test() -> _ { 5 }
15+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
16+
17+
fn test2() -> (_, _) { (5u, 5u) }
18+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
19+
//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures.
20+
21+
static TEST3: _ = "test";
22+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
23+
24+
static TEST4: _ = 145u16;
25+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
26+
27+
static TEST5: (_, _) = (1, 2);
28+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
29+
//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures.
30+
31+
fn test6(_: _) { }
32+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
33+
34+
fn test7(x: _) { let _x: uint = x; }
35+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
36+
37+
fn test8(_f: fn() -> _) { }
38+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
39+
40+
struct Test9;
41+
42+
impl Test9 {
43+
fn test9(&self) -> _ { () }
44+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
45+
46+
fn test10(&self, _x : _) { }
47+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
48+
}
49+
50+
impl Clone for Test9 {
51+
fn clone(&self) -> _ { Test9 }
52+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
53+
54+
fn clone_from(&mut self, other: _) { *self = Test9; }
55+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
56+
}
57+
58+
struct Test10 {
59+
a: _,
60+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
61+
b: (_, _),
62+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
63+
//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures.
64+
}
65+
66+
pub fn main() {
67+
fn fn_test() -> _ { 5 }
68+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
69+
70+
fn fn_test2() -> (_, _) { (5u, 5u) }
71+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
72+
//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures.
73+
74+
static FN_TEST3: _ = "test";
75+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
76+
77+
static FN_TEST4: _ = 145u16;
78+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
79+
80+
static FN_TEST5: (_, _) = (1, 2);
81+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
82+
//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures.
83+
84+
fn fn_test6(_: _) { }
85+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
86+
87+
fn fn_test7(x: _) { let _x: uint = x; }
88+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
89+
90+
fn fn_test8(_f: fn() -> _) { }
91+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
92+
93+
struct FnTest9;
94+
95+
impl FnTest9 {
96+
fn fn_test9(&self) -> _ { () }
97+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
98+
99+
fn fn_test10(&self, _x : _) { }
100+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
101+
}
102+
103+
impl Clone for FnTest9 {
104+
fn clone(&self) -> _ { FnTest9 }
105+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
106+
107+
fn clone_from(&mut self, other: _) { *self = FnTest9; }
108+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
109+
}
110+
111+
struct FnTest10 {
112+
a: _,
113+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
114+
b: (_, _),
115+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures.
116+
//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures.
117+
}
118+
119+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 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+
// This test checks that the `_` type placeholder does not react
12+
// badly if put as a lifetime parameter.
13+
14+
struct Foo<'a, T> {
15+
r: &'a T
16+
}
17+
18+
pub fn main() {
19+
let c: Foo<_, _> = Foo { r: &5u };
20+
//~^ ERROR wrong number of type arguments: expected 1 but found 2
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 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+
// This test checks that the `_` type placeholder does not react
12+
// badly if put as a lifetime parameter.
13+
14+
struct Foo<'a, T> {
15+
r: &'a T
16+
}
17+
18+
pub fn main() {
19+
let c: Foo<_, uint> = Foo { r: &5 };
20+
//~^ ERROR wrong number of type arguments: expected 1 but found 2
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2014 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+
// This test checks that genuine type errors with partial
12+
// type hints are understandable.
13+
14+
struct Foo<T>;
15+
struct Bar<U>;
16+
17+
pub fn main() {
18+
}
19+
20+
fn test1() {
21+
let x: Foo<_> = Bar::<uint>;
22+
//~^ ERROR mismatched types: expected `Foo<<generic #0>>` but found `Bar<uint>`
23+
let y: Foo<uint> = x;
24+
}
25+
26+
fn test2() {
27+
let x: Foo<_> = Bar::<uint>;
28+
//~^ ERROR mismatched types: expected `Foo<<generic #0>>` but found `Bar<uint>`
29+
//~^^ ERROR cannot determine a type for this local variable: unconstrained type
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2014 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+
// This test checks that the `_` type placeholder works
12+
// correctly for enabling type inference.
13+
14+
static CONSTEXPR: *int = &'static 413 as *_;
15+
16+
pub fn main() {
17+
use std::vec_ng::Vec;
18+
19+
let x: Vec<_> = range(0u, 5).collect();
20+
assert_eq!(x.as_slice(), &[0u,1,2,3,4]);
21+
22+
let x = range(0u, 5).collect::<Vec<_>>();
23+
assert_eq!(x.as_slice(), &[0u,1,2,3,4]);
24+
25+
let y: _ = "hello";
26+
assert_eq!(y.len(), 5);
27+
28+
let ptr = &5u;
29+
let ptr2 = ptr as *_;
30+
31+
assert_eq!(ptr as *uint as uint, ptr2 as uint);
32+
}

0 commit comments

Comments
 (0)