From cfee5b7e881d6cfd65557ca98aff043d9b8fea49 Mon Sep 17 00:00:00 2001 From: Barosl Lee Date: Wed, 10 Dec 2014 16:11:19 +0900 Subject: [PATCH] Fix an ICE when trying to resolve a struct variant 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. --- src/librustc/middle/resolve.rs | 34 ++++++++++++++++++++-------- src/test/compile-fail/issue-18252.rs | 2 +- src/test/compile-fail/issue-19452.rs | 17 ++++++++++++++ 3 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/issue-19452.rs diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 36b87bbd423..ebee3650805 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -5769,16 +5769,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 @@ -5791,12 +5805,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()); } _ => { @@ -5813,7 +5827,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 \ @@ -5825,18 +5839,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 { @@ -5846,7 +5860,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 or the MIT license +// , 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 +}