Skip to content

Commit 3a9305c

Browse files
committed
auto merge of #19690 : barosl/rust/struct-variant-as-a-function-ice, r=alexcrichton
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 #19452.
2 parents 10ac5b7 + cfee5b7 commit 3a9305c

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
@@ -5807,16 +5807,30 @@ impl<'a> Resolver<'a> {
58075807
// This is a local path in the value namespace. Walk through
58085808
// scopes looking for it.
58095809

5810+
let path_name = self.path_names_to_string(path);
5811+
58105812
match self.resolve_path(expr.id, path, ValueNS, true) {
5813+
// Check if struct variant
5814+
Some((DefVariant(_, _, true), _)) => {
5815+
self.resolve_error(expr.span,
5816+
format!("`{}` is a struct variant name, but \
5817+
this expression \
5818+
uses it like a function name",
5819+
path_name).as_slice());
5820+
5821+
self.session.span_help(expr.span,
5822+
format!("Did you mean to write: \
5823+
`{} {{ /* fields */ }}`?",
5824+
path_name).as_slice());
5825+
}
58115826
Some(def) => {
58125827
// Write the result into the def map.
58135828
debug!("(resolving expr) resolved `{}`",
5814-
self.path_names_to_string(path));
5829+
path_name);
58155830

58165831
self.record_def(expr.id, def);
58175832
}
58185833
None => {
5819-
let wrong_name = self.path_names_to_string(path);
58205834
// Be helpful if the name refers to a struct
58215835
// (The pattern matching def_tys where the id is in self.structs
58225836
// matches on regular structs while excluding tuple- and enum-like
@@ -5829,12 +5843,12 @@ impl<'a> Resolver<'a> {
58295843
format!("`{}` is a structure name, but \
58305844
this expression \
58315845
uses it like a function name",
5832-
wrong_name).as_slice());
5846+
path_name).as_slice());
58335847

58345848
self.session.span_help(expr.span,
58355849
format!("Did you mean to write: \
58365850
`{} {{ /* fields */ }}`?",
5837-
wrong_name).as_slice());
5851+
path_name).as_slice());
58385852

58395853
}
58405854
_ => {
@@ -5851,7 +5865,7 @@ impl<'a> Resolver<'a> {
58515865
});
58525866

58535867
if method_scope && token::get_name(self.self_name).get()
5854-
== wrong_name {
5868+
== path_name {
58555869
self.resolve_error(
58565870
expr.span,
58575871
"`self` is not available \
@@ -5863,18 +5877,18 @@ impl<'a> Resolver<'a> {
58635877
NoSuggestion => {
58645878
// limit search to 5 to reduce the number
58655879
// of stupid suggestions
5866-
self.find_best_match_for_name(wrong_name.as_slice(), 5)
5880+
self.find_best_match_for_name(path_name.as_slice(), 5)
58675881
.map_or("".to_string(),
58685882
|x| format!("`{}`", x))
58695883
}
58705884
Field =>
5871-
format!("`self.{}`", wrong_name),
5885+
format!("`self.{}`", path_name),
58725886
Method
58735887
| TraitItem =>
5874-
format!("to call `self.{}`", wrong_name),
5888+
format!("to call `self.{}`", path_name),
58755889
TraitMethod(path_str)
58765890
| StaticMethod(path_str) =>
5877-
format!("to call `{}::{}`", path_str, wrong_name)
5891+
format!("to call `{}::{}`", path_str, path_name)
58785892
};
58795893

58805894
if msg.len() > 0 {
@@ -5884,7 +5898,7 @@ impl<'a> Resolver<'a> {
58845898
self.resolve_error(
58855899
expr.span,
58865900
format!("unresolved name `{}`{}",
5887-
wrong_name,
5901+
path_name,
58885902
msg).as_slice());
58895903
}
58905904
}

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)