about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-12-14 09:22:24 +0000
committerbors <bors@rust-lang.org>2014-12-14 09:22:24 +0000
commit3a9305ce823df267fb1afcce76ef06ca09e407ff (patch)
tree75b3af504a1218014bec477c86bd2910899b5b33 /src
parent10ac5b72f1974775bed499105c2a3cf18da98f32 (diff)
parentcfee5b7e881d6cfd65557ca98aff043d9b8fea49 (diff)
downloadrust-3a9305ce823df267fb1afcce76ef06ca09e407ff.tar.gz
rust-3a9305ce823df267fb1afcce76ef06ca09e407ff.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/resolve.rs34
-rw-r--r--src/test/compile-fail/issue-18252.rs2
-rw-r--r--src/test/compile-fail/issue-19452.rs17
3 files changed, 42 insertions, 11 deletions
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 85e0c9294a6..bec3fa77b07 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -5807,16 +5807,30 @@ impl<'a> Resolver<'a> {
                 // This is a local path in the value namespace. Walk through
                 // scopes looking for it.
 
+                let path_name = self.path_names_to_string(path);
+
                 match self.resolve_path(expr.id, path, ValueNS, true) {
+                    // Check if struct variant
+                    Some((DefVariant(_, _, true), _)) => {
+                        self.resolve_error(expr.span,
+                                format!("`{}` is a struct variant name, but \
+                                         this expression \
+                                         uses it like a function name",
+                                        path_name).as_slice());
+
+                        self.session.span_help(expr.span,
+                            format!("Did you mean to write: \
+                                    `{} {{ /* fields */ }}`?",
+                                    path_name).as_slice());
+                    }
                     Some(def) => {
                         // Write the result into the def map.
                         debug!("(resolving expr) resolved `{}`",
-                               self.path_names_to_string(path));
+                               path_name);
 
                         self.record_def(expr.id, def);
                     }
                     None => {
-                        let wrong_name = self.path_names_to_string(path);
                         // Be helpful if the name refers to a struct
                         // (The pattern matching def_tys where the id is in self.structs
                         // matches on regular structs while excluding tuple- and enum-like
@@ -5829,12 +5843,12 @@ impl<'a> Resolver<'a> {
                                         format!("`{}` is a structure name, but \
                                                  this expression \
                                                  uses it like a function name",
-                                                wrong_name).as_slice());
+                                                path_name).as_slice());
 
                                 self.session.span_help(expr.span,
                                     format!("Did you mean to write: \
                                             `{} {{ /* fields */ }}`?",
-                                            wrong_name).as_slice());
+                                            path_name).as_slice());
 
                             }
                             _ => {
@@ -5851,7 +5865,7 @@ impl<'a> Resolver<'a> {
                                 });
 
                                 if method_scope && token::get_name(self.self_name).get()
-                                                                   == wrong_name {
+                                                                   == path_name {
                                         self.resolve_error(
                                             expr.span,
                                             "`self` is not available \
@@ -5863,18 +5877,18 @@ impl<'a> Resolver<'a> {
                                         NoSuggestion => {
                                             // limit search to 5 to reduce the number
                                             // of stupid suggestions
-                                            self.find_best_match_for_name(wrong_name.as_slice(), 5)
+                                            self.find_best_match_for_name(path_name.as_slice(), 5)
                                                                 .map_or("".to_string(),
                                                                         |x| format!("`{}`", x))
                                         }
                                         Field =>
-                                            format!("`self.{}`", wrong_name),
+                                            format!("`self.{}`", path_name),
                                         Method
                                         | TraitItem =>
-                                            format!("to call `self.{}`", wrong_name),
+                                            format!("to call `self.{}`", path_name),
                                         TraitMethod(path_str)
                                         | StaticMethod(path_str) =>
-                                            format!("to call `{}::{}`", path_str, wrong_name)
+                                            format!("to call `{}::{}`", path_str, path_name)
                                     };
 
                                     if msg.len() > 0 {
@@ -5884,7 +5898,7 @@ impl<'a> Resolver<'a> {
                                     self.resolve_error(
                                         expr.span,
                                         format!("unresolved name `{}`{}",
-                                                wrong_name,
+                                                path_name,
                                                 msg).as_slice());
                                 }
                             }
diff --git a/src/test/compile-fail/issue-18252.rs b/src/test/compile-fail/issue-18252.rs
index a655d61fa56..02493b96dc8 100644
--- a/src/test/compile-fail/issue-18252.rs
+++ b/src/test/compile-fail/issue-18252.rs
@@ -13,5 +13,5 @@ enum Foo {
 }
 
 fn main() {
-    let f = Foo::Variant(42u); //~ ERROR expected function, found `Foo`
+    let f = Foo::Variant(42u); //~ ERROR uses it like a function
 }
diff --git a/src/test/compile-fail/issue-19452.rs b/src/test/compile-fail/issue-19452.rs
new file mode 100644
index 00000000000..2270ba594ad
--- /dev/null
+++ b/src/test/compile-fail/issue-19452.rs
@@ -0,0 +1,17 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Homura {
+    Madoka { age: u32 }
+}
+
+fn main() {
+    let homura = Homura::Madoka; //~ ERROR uses it like a function
+}