Skip to content

Commit 7a032a5

Browse files
committed
rollup merge of rust-lang#19690: barosl/struct-variant-as-a-function-ice
Unlike a tuple variant constructor which can be called as a function, a struct variant constructor is not a function, so cannot be called. If the user tries to assign the constructor to a variable, an ICE occurs, because there is no way to use it later. So we should stop the constructor from being used like that. A similar mechanism already exists for a normal struct, as it prohibits a struct from being resolved. This commit does the same for a struct variant. This commit also includes some changes to the existing tests. Fixes rust-lang#19452.
2 parents 9debecb + cfee5b7 commit 7a032a5

File tree

3 files changed

+42
-11
lines changed

3 files changed

+42
-11
lines changed

src/librustc/middle/resolve.rs

+24-10
Original file line numberDiff line numberDiff line change
@@ -5769,16 +5769,30 @@ impl<'a> Resolver<'a> {
57695769
// This is a local path in the value namespace. Walk through
57705770
// scopes looking for it.
57715771

5772+
let path_name = self.path_names_to_string(path);
5773+
57725774
match self.resolve_path(expr.id, path, ValueNS, true) {
5775+
// Check if struct variant
5776+
Some((DefVariant(_, _, true), _)) => {
5777+
self.resolve_error(expr.span,
5778+
format!("`{}` is a struct variant name, but \
5779+
this expression \
5780+
uses it like a function name",
5781+
path_name).as_slice());
5782+
5783+
self.session.span_help(expr.span,
5784+
format!("Did you mean to write: \
5785+
`{} {{ /* fields */ }}`?",
5786+
path_name).as_slice());
5787+
}
57735788
Some(def) => {
57745789
// Write the result into the def map.
57755790
debug!("(resolving expr) resolved `{}`",
5776-
self.path_names_to_string(path));
5791+
path_name);
57775792

57785793
self.record_def(expr.id, def);
57795794
}
57805795
None => {
5781-
let wrong_name = self.path_names_to_string(path);
57825796
// Be helpful if the name refers to a struct
57835797
// (The pattern matching def_tys where the id is in self.structs
57845798
// matches on regular structs while excluding tuple- and enum-like
@@ -5791,12 +5805,12 @@ impl<'a> Resolver<'a> {
57915805
format!("`{}` is a structure name, but \
57925806
this expression \
57935807
uses it like a function name",
5794-
wrong_name).as_slice());
5808+
path_name).as_slice());
57955809

57965810
self.session.span_help(expr.span,
57975811
format!("Did you mean to write: \
57985812
`{} {{ /* fields */ }}`?",
5799-
wrong_name).as_slice());
5813+
path_name).as_slice());
58005814

58015815
}
58025816
_ => {
@@ -5813,7 +5827,7 @@ impl<'a> Resolver<'a> {
58135827
});
58145828

58155829
if method_scope && token::get_name(self.self_name).get()
5816-
== wrong_name {
5830+
== path_name {
58175831
self.resolve_error(
58185832
expr.span,
58195833
"`self` is not available \
@@ -5825,18 +5839,18 @@ impl<'a> Resolver<'a> {
58255839
NoSuggestion => {
58265840
// limit search to 5 to reduce the number
58275841
// of stupid suggestions
5828-
self.find_best_match_for_name(wrong_name.as_slice(), 5)
5842+
self.find_best_match_for_name(path_name.as_slice(), 5)
58295843
.map_or("".to_string(),
58305844
|x| format!("`{}`", x))
58315845
}
58325846
Field =>
5833-
format!("`self.{}`", wrong_name),
5847+
format!("`self.{}`", path_name),
58345848
Method
58355849
| TraitItem =>
5836-
format!("to call `self.{}`", wrong_name),
5850+
format!("to call `self.{}`", path_name),
58375851
TraitMethod(path_str)
58385852
| StaticMethod(path_str) =>
5839-
format!("to call `{}::{}`", path_str, wrong_name)
5853+
format!("to call `{}::{}`", path_str, path_name)
58405854
};
58415855

58425856
if msg.len() > 0 {
@@ -5846,7 +5860,7 @@ impl<'a> Resolver<'a> {
58465860
self.resolve_error(
58475861
expr.span,
58485862
format!("unresolved name `{}`{}",
5849-
wrong_name,
5863+
path_name,
58505864
msg).as_slice());
58515865
}
58525866
}

src/test/compile-fail/issue-18252.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ enum Foo {
1313
}
1414

1515
fn main() {
16-
let f = Foo::Variant(42u); //~ ERROR expected function, found `Foo`
16+
let f = Foo::Variant(42u); //~ ERROR uses it like a function
1717
}

src/test/compile-fail/issue-19452.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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+
enum Homura {
12+
Madoka { age: u32 }
13+
}
14+
15+
fn main() {
16+
let homura = Homura::Madoka; //~ ERROR uses it like a function
17+
}

0 commit comments

Comments
 (0)