rust/src/librustc_resolve/lib.rs

3603 lines
148 KiB
Rust
Raw Normal View History

// Copyright 2012-2015 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.
#![crate_name = "rustc_resolve"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]
2015-04-28 16:36:22 -07:00
#![feature(associated_consts)]
#![feature(borrow_state)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
2015-10-26 20:31:11 +01:00
#[macro_use]
extern crate log;
#[macro_use]
extern crate syntax;
extern crate arena;
2015-10-26 20:31:11 +01:00
#[macro_use]
extern crate rustc;
use self::PatternBindingMode::*;
use self::Namespace::*;
use self::ResolveResult::*;
use self::FallbackSuggestion::*;
use self::TypeParameters::*;
use self::RibKind::*;
use self::UseLexicalScopeFlag::*;
use self::ModulePrefixResult::*;
use self::AssocItemResolveResult::*;
use self::BareIdentifierPatternResolution::*;
use self::ParentLink::*;
use rustc::dep_graph::DepNode;
2016-03-29 08:50:44 +03:00
use rustc::hir::map as hir_map;
use rustc::session::Session;
use rustc::lint;
use rustc::hir::def::*;
use rustc::hir::def_id::DefId;
use rustc::hir::pat_util::pat_bindings;
use rustc::ty;
use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace};
2016-04-19 22:43:10 +09:00
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
use syntax::ast::{self, FloatTy};
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
use syntax::codemap::{self, Span, Pos};
2015-12-21 10:00:43 +13:00
use syntax::errors::DiagnosticBuilder;
use syntax::parse::token::{self, keywords};
use syntax::util::lev_distance::find_best_match_for_name;
2015-07-31 00:04:06 -07:00
2016-03-29 08:50:44 +03:00
use rustc::hir::intravisit::{self, FnKind, Visitor};
use rustc::hir;
use rustc::hir::{Arm, BindByRef, BindByValue, BindingMode, Block};
use rustc::hir::Crate;
use rustc::hir::{Expr, ExprAgain, ExprBreak, ExprField};
2016-03-29 08:50:44 +03:00
use rustc::hir::{ExprLoop, ExprWhile, ExprMethodCall};
use rustc::hir::{ExprPath, ExprStruct, FnDecl};
use rustc::hir::{ForeignItemFn, ForeignItemStatic, Generics};
use rustc::hir::{ImplItem, Item, ItemConst, ItemEnum, ItemExternCrate};
use rustc::hir::{ItemFn, ItemForeignMod, ItemImpl, ItemMod, ItemStatic, ItemDefaultImpl};
use rustc::hir::{ItemStruct, ItemTrait, ItemTy, ItemUse};
use rustc::hir::Local;
use rustc::hir::{Pat, PatKind, Path, PrimTy};
use rustc::hir::{PathSegment, PathParameters};
use rustc::hir::HirVec;
use rustc::hir::{TraitRef, Ty, TyBool, TyChar, TyFloat, TyInt};
use rustc::hir::{TyRptr, TyStr, TyUint, TyPath};
use std::collections::{HashMap, HashSet};
2013-12-20 21:14:25 -08:00
use std::cell::{Cell, RefCell};
use std::fmt;
use std::mem::replace;
use resolve_imports::{ImportDirective, NameResolution};
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
2016-03-17 01:05:29 +00:00
mod diagnostics;
2014-12-10 19:46:38 -08:00
mod check_unused;
mod build_reduced_graph;
mod resolve_imports;
enum SuggestionType {
Macro(String),
Function(token::InternedString),
NotFound,
}
/// Candidates for a name resolution failure
2016-03-17 01:05:29 +00:00
struct SuggestedCandidates {
name: String,
candidates: Vec<Path>,
}
2016-03-17 01:05:29 +00:00
enum ResolutionError<'a> {
/// error E0401: can't use type parameters from outer function
TypeParametersFromOuterFunction,
/// error E0402: cannot use an outer type parameter in this context
OuterTypeParameterContext,
/// error E0403: the name is already used for a type parameter in this type parameter list
2015-07-14 19:42:38 +02:00
NameAlreadyUsedInTypeParameterList(Name),
/// error E0404: is not a trait
2015-07-14 19:42:38 +02:00
IsNotATrait(&'a str),
/// error E0405: use of undeclared trait name
UndeclaredTraitName(&'a str, SuggestedCandidates),
/// error E0406: undeclared associated type
UndeclaredAssociatedType,
/// error E0407: method is not a member of trait
2015-07-14 19:42:38 +02:00
MethodNotMemberOfTrait(Name, &'a str),
/// error E0437: type is not a member of trait
TypeNotMemberOfTrait(Name, &'a str),
/// error E0438: const is not a member of trait
ConstNotMemberOfTrait(Name, &'a str),
/// error E0408: variable `{}` from pattern #1 is not bound in pattern
2015-07-14 19:42:38 +02:00
VariableNotBoundInPattern(Name, usize),
/// error E0409: variable is bound with different mode in pattern #{} than in pattern #1
2015-07-14 19:42:38 +02:00
VariableBoundWithDifferentMode(Name, usize),
/// error E0410: variable from pattern is not bound in pattern #1
2015-07-14 19:42:38 +02:00
VariableNotBoundInParentPattern(Name, usize),
/// error E0411: use of `Self` outside of an impl or trait
SelfUsedOutsideImplOrTrait,
/// error E0412: use of undeclared
UseOfUndeclared(&'a str, &'a str, SuggestedCandidates),
/// error E0413: declaration shadows an enum variant or unit-like struct in scope
2015-07-14 19:42:38 +02:00
DeclarationShadowsEnumVariantOrUnitLikeStruct(Name),
/// error E0414: only irrefutable patterns allowed here
ConstantForIrrefutableBinding(Name),
/// error E0415: identifier is bound more than once in this parameter list
2015-07-14 19:42:38 +02:00
IdentifierBoundMoreThanOnceInParameterList(&'a str),
/// error E0416: identifier is bound more than once in the same pattern
2015-07-14 19:42:38 +02:00
IdentifierBoundMoreThanOnceInSamePattern(&'a str),
/// error E0417: static variables cannot be referenced in a pattern
StaticVariableReference(&'a NameBinding<'a>),
/// error E0418: is not an enum variant, struct or const
2015-07-14 19:42:38 +02:00
NotAnEnumVariantStructOrConst(&'a str),
/// error E0419: unresolved enum variant, struct or const
2015-07-14 19:42:38 +02:00
UnresolvedEnumVariantStructOrConst(&'a str),
/// error E0420: is not an associated const
2015-07-14 19:42:38 +02:00
NotAnAssociatedConst(&'a str),
/// error E0421: unresolved associated const
2015-07-14 19:42:38 +02:00
UnresolvedAssociatedConst(&'a str),
/// error E0422: does not name a struct
2015-07-14 19:42:38 +02:00
DoesNotNameAStruct(&'a str),
/// error E0423: is a struct variant name, but this expression uses it like a function name
2015-07-14 19:42:38 +02:00
StructVariantUsedAsFunction(&'a str),
/// error E0424: `self` is not available in a static method
SelfNotAvailableInStaticMethod,
/// error E0425: unresolved name
UnresolvedName(&'a str, &'a str, UnresolvedNameContext<'a>),
/// error E0426: use of undeclared label
2015-07-14 19:42:38 +02:00
UndeclaredLabel(&'a str),
/// error E0427: cannot use `ref` binding mode with ...
2015-07-14 19:42:38 +02:00
CannotUseRefBindingModeWith(&'a str),
/// error E0429: `self` imports are only allowed within a { } list
SelfImportsOnlyAllowedWithin,
/// error E0430: `self` import can only appear once in the list
SelfImportCanOnlyAppearOnceInTheList,
/// error E0431: `self` import can only appear in an import list with a non-empty prefix
SelfImportOnlyInImportListWithNonEmptyPrefix,
/// error E0432: unresolved import
UnresolvedImport(Option<(&'a str, &'a str)>),
/// error E0433: failed to resolve
2015-07-14 19:42:38 +02:00
FailedToResolve(&'a str),
/// error E0434: can't capture dynamic environment in a fn item
CannotCaptureDynamicEnvironmentInFnItem,
/// error E0435: attempt to use a non-constant value in a constant
AttemptToUseNonConstantValueInConstant,
}
/// Context of where `ResolutionError::UnresolvedName` arose.
#[derive(Clone, PartialEq, Eq, Debug)]
enum UnresolvedNameContext<'a> {
/// `PathIsMod(parent)` indicates that a given path, used in
/// expression context, actually resolved to a module rather than
/// a value. The optional expression attached to the variant is the
/// the parent of the erroneous path expression.
PathIsMod(Option<&'a Expr>),
/// `Other` means we have no extra information about the context
/// of the unresolved name error. (Maybe we could eliminate all
/// such cases; but for now, this is an information-free default.)
Other,
}
fn resolve_error<'b, 'a: 'b, 'tcx: 'a, 'c>(resolver: &'b Resolver<'a, 'tcx>,
span: syntax::codemap::Span,
resolution_error: ResolutionError<'c>) {
2015-12-23 19:27:20 +13:00
resolve_struct_error(resolver, span, resolution_error).emit();
2015-12-21 10:00:43 +13:00
}
fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a, 'c>(resolver: &'b Resolver<'a, 'tcx>,
span: syntax::codemap::Span,
resolution_error: ResolutionError<'b>)
-> DiagnosticBuilder<'c> {
2015-07-14 19:42:38 +02:00
if !resolver.emit_errors {
2015-12-23 19:27:20 +13:00
return resolver.session.diagnostic().struct_dummy();
2015-07-14 19:42:38 +02:00
}
2015-12-21 10:00:43 +13:00
2015-12-23 19:27:20 +13:00
match resolution_error {
2015-07-14 19:42:38 +02:00
ResolutionError::TypeParametersFromOuterFunction => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0401,
"can't use type parameters from outer function; try using a local \
type parameter instead")
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::OuterTypeParameterContext => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0402,
"cannot use an outer type parameter in this context")
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::NameAlreadyUsedInTypeParameterList(name) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0403,
"the name `{}` is already used for a type parameter in this type \
parameter list",
name)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::IsNotATrait(name) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session, span, E0404, "`{}` is not a trait", name)
2015-10-26 20:31:11 +01:00
}
ResolutionError::UndeclaredTraitName(name, candidates) => {
let mut err = struct_span_err!(resolver.session,
span,
E0405,
"trait `{}` is not in scope",
name);
show_candidates(&mut err, &candidates);
err
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::UndeclaredAssociatedType => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session, span, E0406, "undeclared associated type")
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0407,
"method `{}` is not a member of trait `{}`",
method,
trait_)
2015-10-26 20:31:11 +01:00
}
ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0437,
"type `{}` is not a member of trait `{}`",
type_,
trait_)
2015-10-26 20:31:11 +01:00
}
ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0438,
"const `{}` is not a member of trait `{}`",
const_,
trait_)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::VariableNotBoundInPattern(variable_name, pattern_number) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0408,
"variable `{}` from pattern #1 is not bound in pattern #{}",
variable_name,
pattern_number)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::VariableBoundWithDifferentMode(variable_name, pattern_number) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0409,
"variable `{}` is bound with different mode in pattern #{} than in \
pattern #1",
variable_name,
pattern_number)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::VariableNotBoundInParentPattern(variable_name, pattern_number) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0410,
"variable `{}` from pattern #{} is not bound in pattern #1",
variable_name,
pattern_number)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::SelfUsedOutsideImplOrTrait => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0411,
"use of `Self` outside of an impl or trait")
2015-10-26 20:31:11 +01:00
}
ResolutionError::UseOfUndeclared(kind, name, candidates) => {
let mut err = struct_span_err!(resolver.session,
span,
E0412,
"{} `{}` is undefined or not in scope",
kind,
name);
show_candidates(&mut err, &candidates);
err
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(name) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0413,
"declaration of `{}` shadows an enum variant \
or unit-like struct in scope",
name)
2015-10-26 20:31:11 +01:00
}
ResolutionError::ConstantForIrrefutableBinding(name) => {
2015-12-21 10:00:43 +13:00
let mut err = struct_span_err!(resolver.session,
span,
E0414,
"variable bindings cannot shadow constants");
2015-12-21 10:00:43 +13:00
err.span_note(span,
"there already is a constant in scope sharing the same \
name as this pattern");
if let Some(binding) = resolver.current_module
.resolve_name_in_lexical_scope(name, ValueNS) {
let participle = if binding.is_import() { "imported" } else { "defined" };
err.span_note(binding.span, &format!("constant {} here", participle));
}
2015-12-21 10:00:43 +13:00
err
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0415,
"identifier `{}` is bound more than once in this parameter list",
identifier)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0416,
"identifier `{}` is bound more than once in the same pattern",
identifier)
2015-10-26 20:31:11 +01:00
}
ResolutionError::StaticVariableReference(binding) => {
let mut err = struct_span_err!(resolver.session,
span,
E0417,
"static variables cannot be referenced in a \
pattern, use a `const` instead");
if binding.span != codemap::DUMMY_SP {
let participle = if binding.is_import() { "imported" } else { "defined" };
err.span_note(binding.span, &format!("static variable {} here", participle));
}
err
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::NotAnEnumVariantStructOrConst(name) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0418,
"`{}` is not an enum variant, struct or const",
name)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::UnresolvedEnumVariantStructOrConst(name) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0419,
"unresolved enum variant, struct or const `{}`",
name)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::NotAnAssociatedConst(name) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0420,
"`{}` is not an associated const",
name)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::UnresolvedAssociatedConst(name) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0421,
"unresolved associated const `{}`",
name)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::DoesNotNameAStruct(name) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0422,
"`{}` does not name a structure",
name)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::StructVariantUsedAsFunction(path_name) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0423,
"`{}` is the name of a struct or struct variant, but this expression \
uses it like a function name",
path_name)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::SelfNotAvailableInStaticMethod => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0424,
"`self` is not available in a static method. Maybe a `self` \
argument is missing?")
2015-10-26 20:31:11 +01:00
}
ResolutionError::UnresolvedName(path, msg, context) => {
2015-12-24 10:54:37 +13:00
let mut err = struct_span_err!(resolver.session,
span,
E0425,
"unresolved name `{}`{}",
path,
msg);
match context {
2015-12-24 20:44:14 +01:00
UnresolvedNameContext::Other => { } // no help available
UnresolvedNameContext::PathIsMod(parent) => {
err.help(&match parent.map(|parent| &parent.node) {
Some(&ExprField(_, ident)) => {
format!("To reference an item from the `{module}` module, \
use `{module}::{ident}`",
module = path,
ident = ident.node)
}
Some(&ExprMethodCall(ident, _, _)) => {
format!("To call a function from the `{module}` module, \
use `{module}::{ident}(..)`",
module = path,
ident = ident.node)
}
_ => {
format!("Module `{module}` cannot be used as an expression",
module = path)
}
});
}
}
2015-12-21 10:00:43 +13:00
err
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::UndeclaredLabel(name) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0426,
"use of undeclared label `{}`",
name)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::CannotUseRefBindingModeWith(descr) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0427,
"cannot use `ref` binding mode with {}",
descr)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::SelfImportsOnlyAllowedWithin => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0429,
"{}",
"`self` imports are only allowed within a { } list")
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0430,
"`self` import can only appear once in the list")
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0431,
"`self` import can only appear in an import list with a \
non-empty prefix")
}
2015-07-14 19:42:38 +02:00
ResolutionError::UnresolvedImport(name) => {
let msg = match name {
Some((n, p)) => format!("unresolved import `{}`{}", n, p),
2015-10-26 20:31:11 +01:00
None => "unresolved import".to_owned(),
};
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session, span, E0432, "{}", msg)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::FailedToResolve(msg) => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session, span, E0433, "failed to resolve. {}", msg)
2015-10-26 20:31:11 +01:00
}
2015-07-14 19:42:38 +02:00
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0434,
"{}",
"can't capture dynamic environment in a fn item; use the || { ... } \
closure form instead")
2015-10-26 20:31:11 +01:00
}
ResolutionError::AttemptToUseNonConstantValueInConstant => {
2015-12-21 10:00:43 +13:00
struct_span_err!(resolver.session,
span,
E0435,
"attempt to use a non-constant value in a constant")
2015-10-26 20:31:11 +01:00
}
2015-12-23 19:27:20 +13:00
}
}
2015-03-30 09:38:44 -04:00
#[derive(Copy, Clone)]
struct BindingInfo {
span: Span,
binding_mode: BindingMode,
}
// Map from the name in a pattern to its binding mode.
type BindingMap = HashMap<Name, BindingInfo>;
2015-03-30 09:38:44 -04:00
#[derive(Copy, Clone, PartialEq)]
2013-10-02 14:33:01 +02:00
enum PatternBindingMode {
RefutableMode,
LocalIrrefutableMode,
ArgumentIrrefutableMode,
}
2015-03-30 09:38:44 -04:00
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Namespace {
TypeNS,
2015-10-26 20:31:11 +01:00
ValueNS,
}
impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
fn visit_nested_item(&mut self, item: hir::ItemId) {
self.visit_item(self.ast_map.expect_item(item.id))
}
fn visit_item(&mut self, item: &Item) {
self.resolve_item(item);
}
fn visit_arm(&mut self, arm: &Arm) {
self.resolve_arm(arm);
}
fn visit_block(&mut self, block: &Block) {
self.resolve_block(block);
}
fn visit_expr(&mut self, expr: &Expr) {
self.resolve_expr(expr, None);
}
fn visit_local(&mut self, local: &Local) {
self.resolve_local(local);
}
fn visit_ty(&mut self, ty: &Ty) {
self.resolve_type(ty);
}
fn visit_generics(&mut self, generics: &Generics) {
self.resolve_generics(generics);
}
2015-10-26 20:31:11 +01:00
fn visit_poly_trait_ref(&mut self, tref: &hir::PolyTraitRef, m: &hir::TraitBoundModifier) {
match self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0) {
Ok(def) => self.record_def(tref.trait_ref.ref_id, def),
2015-10-26 20:31:11 +01:00
Err(_) => {
// error already reported
2015-12-11 20:59:11 +13:00
self.record_def(tref.trait_ref.ref_id, err_path_resolution())
2015-10-26 20:31:11 +01:00
}
}
intravisit::walk_poly_trait_ref(self, tref, m);
}
2015-10-26 20:31:11 +01:00
fn visit_variant(&mut self,
variant: &hir::Variant,
generics: &Generics,
item_id: ast::NodeId) {
if let Some(ref dis_expr) = variant.node.disr_expr {
// resolve the discriminator expr as a constant
self.with_constant_rib(|this| {
this.visit_expr(dis_expr);
});
}
// `intravisit::walk_variant` without the discriminant expression.
2015-10-26 20:31:11 +01:00
self.visit_variant_data(&variant.node.data,
variant.node.name,
generics,
item_id,
variant.span);
}
2015-07-31 00:04:06 -07:00
fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem) {
let type_parameters = match foreign_item.node {
ForeignItemFn(_, ref generics) => {
HasTypeParameters(generics, FnSpace, ItemRibKind)
}
2015-10-26 20:31:11 +01:00
ForeignItemStatic(..) => NoTypeParameters,
};
self.with_type_parameter_rib(type_parameters, |this| {
intravisit::walk_foreign_item(this, foreign_item);
});
}
fn visit_fn(&mut self,
function_kind: FnKind<'v>,
declaration: &'v FnDecl,
block: &'v Block,
_: Span,
node_id: NodeId) {
let rib_kind = match function_kind {
FnKind::ItemFn(_, generics, _, _, _, _, _) => {
self.visit_generics(generics);
ItemRibKind
}
FnKind::Method(_, sig, _, _) => {
self.visit_generics(&sig.generics);
self.visit_explicit_self(&sig.explicit_self);
MethodRibKind
}
FnKind::Closure(_) => ClosureRibKind(node_id),
};
self.resolve_function(rib_kind, declaration, block);
}
}
pub type ErrorMessage = Option<(Span, String)>;
#[derive(Clone, PartialEq, Eq)]
pub enum ResolveResult<T> {
2015-10-26 20:31:11 +01:00
Failed(ErrorMessage), // Failed to resolve the name, optional helpful error message.
Indeterminate, // Couldn't determine due to unresolved globs.
Success(T), // Successfully resolved the import.
}
impl<T> ResolveResult<T> {
2016-01-16 11:41:19 +00:00
fn and_then<U, F: FnOnce(T) -> ResolveResult<U>>(self, f: F) -> ResolveResult<U> {
match self {
Failed(msg) => Failed(msg),
Indeterminate => Indeterminate,
Success(t) => f(t),
2015-10-26 20:31:11 +01:00
}
}
fn success(self) -> Option<T> {
match self {
Success(t) => Some(t),
_ => None,
}
}
}
enum FallbackSuggestion {
NoSuggestion,
Field,
TraitItem,
TraitMethod(String),
}
2015-03-30 09:38:44 -04:00
#[derive(Copy, Clone)]
enum TypeParameters<'tcx, 'a> {
NoTypeParameters,
2015-10-26 20:31:11 +01:00
HasTypeParameters(// Type parameters.
&'a Generics,
2015-10-26 20:31:11 +01:00
// Identifies the things that these parameters
// were declared on (type, fn, etc)
ParamSpace,
2015-10-26 20:31:11 +01:00
// The kind of the rib used for type parameters.
RibKind<'tcx>),
}
// The rib kind controls the translation of local
// definitions (`Def::Local`) to upvars (`Def::Upvar`).
2015-03-30 09:38:44 -04:00
#[derive(Copy, Clone, Debug)]
enum RibKind<'a> {
// No translation needs to be applied.
NormalRibKind,
// We passed through a closure scope at the given node ID.
// Translate upvars as appropriate.
ClosureRibKind(NodeId /* func id */),
// We passed through an impl or trait and are now in one of its
2013-06-06 10:38:41 +03:00
// methods. Allow references to ty params that impl or trait
// binds. Disallow any other upvars (including other ty params that are
// upvars).
MethodRibKind,
// We passed through an item scope. Disallow upvars.
ItemRibKind,
// We're in a constant item. Can't refer to dynamic stuff.
2015-10-26 20:31:11 +01:00
ConstantItemRibKind,
// We passed through a module.
ModuleRibKind(Module<'a>),
}
2015-03-30 09:38:44 -04:00
#[derive(Copy, Clone)]
2013-10-02 14:33:01 +02:00
enum UseLexicalScopeFlag {
DontUseLexicalScope,
2015-10-26 20:31:11 +01:00
UseLexicalScope,
}
enum ModulePrefixResult<'a> {
NoPrefixFound,
PrefixFound(Module<'a>, usize),
}
#[derive(Copy, Clone)]
enum AssocItemResolveResult {
/// Syntax such as `<T>::item`, which can't be resolved until type
/// checking.
TypecheckRequired,
/// We should have been able to resolve the associated item.
ResolveAttempt(Option<PathResolution>),
}
2015-03-30 09:38:44 -04:00
#[derive(Copy, Clone)]
2013-10-02 14:33:01 +02:00
enum BareIdentifierPatternResolution {
2016-02-25 03:36:17 +00:00
FoundStructOrEnumVariant(Def),
FoundConst(Def, Name),
2015-10-26 20:31:11 +01:00
BareIdentifierPatternUnresolved,
}
/// One local scope.
2015-01-28 08:34:18 -05:00
#[derive(Debug)]
struct Rib<'a> {
bindings: HashMap<Name, Def>,
kind: RibKind<'a>,
2012-09-05 15:58:43 -07:00
}
impl<'a> Rib<'a> {
fn new(kind: RibKind<'a>) -> Rib<'a> {
Rib {
bindings: HashMap::new(),
2015-10-26 20:31:11 +01:00
kind: kind,
}
}
}
/// A definition along with the index of the rib it was found on
struct LocalDef {
ribs: Option<(Namespace, usize)>,
2015-10-26 20:31:11 +01:00
def: Def,
}
impl LocalDef {
fn from_def(def: Def) -> Self {
LocalDef {
ribs: None,
2015-10-26 20:31:11 +01:00
def: def,
}
}
}
enum LexicalScopeBinding<'a> {
Item(&'a NameBinding<'a>),
LocalDef(LocalDef),
}
impl<'a> LexicalScopeBinding<'a> {
fn local_def(self) -> LocalDef {
match self {
LexicalScopeBinding::LocalDef(local_def) => local_def,
LexicalScopeBinding::Item(binding) => LocalDef::from_def(binding.def().unwrap()),
}
}
fn module(self) -> Option<Module<'a>> {
match self {
LexicalScopeBinding::Item(binding) => binding.module(),
_ => None,
}
}
}
/// The link from a module up to its nearest parent node.
2015-01-28 08:34:18 -05:00
#[derive(Clone,Debug)]
enum ParentLink<'a> {
NoParentLink,
ModuleParentLink(Module<'a>, Name),
BlockParentLink(Module<'a>, NodeId),
}
/// One node in the tree of modules.
pub struct ModuleS<'a> {
parent_link: ParentLink<'a>,
2016-01-31 00:41:26 +00:00
def: Option<Def>,
// If the module is an extern crate, `def` is root of the external crate and `extern_crate_id`
// is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None).
extern_crate_id: Option<NodeId>,
resolutions: RefCell<HashMap<(Name, Namespace), &'a RefCell<NameResolution<'a>>>>,
unresolved_imports: RefCell<Vec<&'a ImportDirective<'a>>>,
2016-03-09 01:46:46 +00:00
prelude: RefCell<Option<Module<'a>>>,
glob_importers: RefCell<Vec<(Module<'a>, &'a ImportDirective<'a>)>>,
globs: RefCell<Vec<&'a ImportDirective<'a>>>,
2016-04-18 00:00:18 +00:00
// Used to memoize the traits in this module for faster searches through all traits in scope.
2016-04-25 05:34:59 +00:00
traits: RefCell<Option<Box<[(Name, &'a NameBinding<'a>)]>>>,
2016-04-18 00:00:18 +00:00
// Whether this module is populated. If not populated, any attempt to
// access the children must be preceded with a
// `populate_module_if_necessary` call.
populated: Cell<bool>,
arenas: &'a ResolverArenas<'a>,
}
pub type Module<'a> = &'a ModuleS<'a>;
impl<'a> ModuleS<'a> {
fn new(parent_link: ParentLink<'a>,
def: Option<Def>,
external: bool,
arenas: &'a ResolverArenas<'a>) -> Self {
ModuleS {
parent_link: parent_link,
2016-01-31 00:41:26 +00:00
def: def,
extern_crate_id: None,
resolutions: RefCell::new(HashMap::new()),
unresolved_imports: RefCell::new(Vec::new()),
2016-03-09 01:46:46 +00:00
prelude: RefCell::new(None),
glob_importers: RefCell::new(Vec::new()),
globs: RefCell::new((Vec::new())),
2016-04-18 00:00:18 +00:00
traits: RefCell::new(None),
populated: Cell::new(!external),
arenas: arenas
}
2012-09-05 15:58:43 -07:00
}
fn for_each_child<F: FnMut(Name, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
for (&(name, ns), name_resolution) in self.resolutions.borrow().iter() {
name_resolution.borrow().binding.map(|binding| f(name, ns, binding));
}
}
fn def_id(&self) -> Option<DefId> {
2016-01-31 00:41:26 +00:00
self.def.as_ref().map(Def::def_id)
}
// `self` resolves to the first module ancestor that `is_normal`.
fn is_normal(&self) -> bool {
2016-01-31 00:41:26 +00:00
match self.def {
Some(Def::Mod(_)) => true,
_ => false,
}
}
fn is_trait(&self) -> bool {
2016-01-31 00:41:26 +00:00
match self.def {
Some(Def::Trait(_)) => true,
_ => false,
}
2012-09-05 15:58:43 -07:00
}
2015-08-06 12:47:10 +02:00
}
impl<'a> fmt::Debug for ModuleS<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2016-04-26 04:20:50 +00:00
write!(f, "{:?}", self.def)
}
}
2015-11-17 09:10:41 +00:00
// Records a possibly-private value, type, or module definition.
#[derive(Clone, Debug)]
pub struct NameBinding<'a> {
kind: NameBindingKind<'a>,
span: Span,
vis: ty::Visibility,
}
#[derive(Clone, Debug)]
enum NameBindingKind<'a> {
2015-11-17 09:10:41 +00:00
Def(Def),
Module(Module<'a>),
Import {
binding: &'a NameBinding<'a>,
2016-04-17 01:57:09 +00:00
directive: &'a ImportDirective<'a>,
// Some(error) if using this imported name causes the import to be a privacy error
privacy_error: Option<Box<PrivacyError<'a>>>,
},
}
#[derive(Clone, Debug)]
struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>);
impl<'a> NameBinding<'a> {
fn module(&self) -> Option<Module<'a>> {
match self.kind {
NameBindingKind::Module(module) => Some(module),
NameBindingKind::Def(_) => None,
NameBindingKind::Import { binding, .. } => binding.module(),
}
}
fn def(&self) -> Option<Def> {
match self.kind {
NameBindingKind::Def(def) => Some(def),
NameBindingKind::Module(module) => module.def,
NameBindingKind::Import { binding, .. } => binding.def(),
}
}
fn is_pseudo_public(&self) -> bool {
self.pseudo_vis() == ty::Visibility::Public
}
// We sometimes need to treat variants as `pub` for backwards compatibility
fn pseudo_vis(&self) -> ty::Visibility {
if self.is_variant() { ty::Visibility::Public } else { self.vis }
}
fn is_variant(&self) -> bool {
match self.kind {
NameBindingKind::Def(Def::Variant(..)) => true,
_ => false,
}
}
fn is_extern_crate(&self) -> bool {
self.module().and_then(|module| module.extern_crate_id).is_some()
}
fn is_import(&self) -> bool {
match self.kind {
NameBindingKind::Import { .. } => true,
_ => false,
}
}
2016-04-17 01:57:09 +00:00
fn is_glob_import(&self) -> bool {
match self.kind {
NameBindingKind::Import { directive, .. } => directive.is_glob(),
_ => false,
}
}
fn is_importable(&self) -> bool {
match self.def().unwrap() {
Def::AssociatedConst(..) | Def::Method(..) | Def::AssociatedTy(..) => false,
_ => true,
}
}
}
/// Interns the names of the primitive types.
2013-10-02 14:33:01 +02:00
struct PrimitiveTypeTable {
primitive_types: HashMap<Name, PrimTy>,
}
impl PrimitiveTypeTable {
fn new() -> PrimitiveTypeTable {
2015-10-26 20:31:11 +01:00
let mut table = PrimitiveTypeTable { primitive_types: HashMap::new() };
table.intern("bool", TyBool);
table.intern("char", TyChar);
table.intern("f32", TyFloat(FloatTy::F32));
table.intern("f64", TyFloat(FloatTy::F64));
table.intern("isize", TyInt(IntTy::Is));
table.intern("i8", TyInt(IntTy::I8));
table.intern("i16", TyInt(IntTy::I16));
table.intern("i32", TyInt(IntTy::I32));
table.intern("i64", TyInt(IntTy::I64));
2015-10-26 20:31:11 +01:00
table.intern("str", TyStr);
table.intern("usize", TyUint(UintTy::Us));
table.intern("u8", TyUint(UintTy::U8));
table.intern("u16", TyUint(UintTy::U16));
table.intern("u32", TyUint(UintTy::U32));
table.intern("u64", TyUint(UintTy::U64));
table
}
fn intern(&mut self, string: &str, primitive_type: PrimTy) {
self.primitive_types.insert(token::intern(string), primitive_type);
}
}
/// The main resolver class.
2015-10-26 20:31:11 +01:00
pub struct Resolver<'a, 'tcx: 'a> {
2014-03-05 16:36:01 +02:00
session: &'a Session,
2015-07-31 00:04:06 -07:00
ast_map: &'a hir_map::Map<'tcx>,
graph_root: Module<'a>,
2016-04-26 08:29:13 +00:00
trait_item_map: FnvHashMap<(Name, DefId), bool /* is static method? */>,
structs: FnvHashMap<DefId, Vec<Name>>,
// The number of imports that are currently unresolved.
unresolved_imports: usize,
// The module that represents the current item scope.
current_module: Module<'a>,
// The current set of local scopes, for values.
// FIXME #4948: Reuse ribs to avoid allocation.
value_ribs: Vec<Rib<'a>>,
// The current set of local scopes, for types.
type_ribs: Vec<Rib<'a>>,
// The current set of local scopes, for labels.
label_ribs: Vec<Rib<'a>>,
// The trait that the current context can refer to.
current_trait_ref: Option<(DefId, TraitRef)>,
// The current self type if inside an impl (used for better errors).
current_self_type: Option<Ty>,
2012-09-19 18:52:49 -07:00
// The idents for the primitive types.
2014-04-14 11:30:59 +03:00
primitive_type_table: PrimitiveTypeTable,
def_map: DefMap,
freevars: FreevarMap,
freevars_seen: NodeMap<NodeMap<usize>>,
export_map: ExportMap,
2012-09-06 19:40:15 -07:00
trait_map: TraitMap,
// A map from nodes to modules, both normal (`mod`) modules and anonymous modules.
// Anonymous modules are pseudo-modules that are implicitly created around items
// contained within blocks.
//
// For example, if we have this:
//
// fn f() {
// fn g() {
// ...
// }
// }
//
// There will be an anonymous module created around `g` with the ID of the
// entry block for `f`.
module_map: NodeMap<Module<'a>>,
// Whether or not to print error messages. Can be set to true
// when getting additional info for error message suggestions,
// so as to avoid printing duplicate errors
emit_errors: bool,
make_glob_map: bool,
// Maps imports to the names of items actually imported (this actually maps
// all imports, but only glob imports are actually interesting).
glob_map: GlobMap,
used_imports: HashSet<(NodeId, Namespace)>,
2014-09-11 19:14:43 +02:00
used_crates: HashSet<CrateNum>,
2016-04-19 22:43:10 +09:00
maybe_unused_trait_imports: NodeSet,
privacy_errors: Vec<PrivacyError<'a>>,
arenas: &'a ResolverArenas<'a>,
}
2016-03-17 01:05:29 +00:00
struct ResolverArenas<'a> {
modules: arena::TypedArena<ModuleS<'a>>,
local_modules: RefCell<Vec<Module<'a>>>,
name_bindings: arena::TypedArena<NameBinding<'a>>,
import_directives: arena::TypedArena<ImportDirective<'a>>,
name_resolutions: arena::TypedArena<RefCell<NameResolution<'a>>>,
2016-02-15 02:22:59 +00:00
}
impl<'a> ResolverArenas<'a> {
fn alloc_module(&'a self, module: ModuleS<'a>) -> Module<'a> {
let module = self.modules.alloc(module);
if module.def_id().map(|def_id| def_id.is_local()).unwrap_or(true) {
self.local_modules.borrow_mut().push(module);
}
module
}
fn local_modules(&'a self) -> ::std::cell::Ref<'a, Vec<Module<'a>>> {
self.local_modules.borrow()
}
fn alloc_name_binding(&'a self, name_binding: NameBinding<'a>) -> &'a NameBinding<'a> {
self.name_bindings.alloc(name_binding)
}
fn alloc_import_directive(&'a self, import_directive: ImportDirective<'a>)
-> &'a ImportDirective {
2016-02-15 02:22:59 +00:00
self.import_directives.alloc(import_directive)
}
fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> {
self.name_resolutions.alloc(Default::default())
}
}
impl<'a, 'tcx> ty::NodeIdTree for Resolver<'a, 'tcx> {
fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
let ancestor = self.ast_map.local_def_id(ancestor);
let mut module = *self.module_map.get(&node).unwrap();
2016-04-27 19:30:16 +00:00
while module.def_id() != Some(ancestor) {
let module_parent = match self.get_nearest_normal_module_parent(module) {
Some(parent) => parent,
None => return false,
};
module = module_parent;
}
2016-04-27 19:30:16 +00:00
true
}
}
impl<'a, 'tcx> Resolver<'a, 'tcx> {
fn new(session: &'a Session,
2015-07-31 00:04:06 -07:00
ast_map: &'a hir_map::Map<'tcx>,
make_glob_map: MakeGlobMap,
arenas: &'a ResolverArenas<'a>)
2015-10-26 20:31:11 +01:00
-> Resolver<'a, 'tcx> {
let root_def_id = ast_map.local_def_id(CRATE_NODE_ID);
let graph_root =
2016-04-26 04:20:50 +00:00
ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, arenas);
let graph_root = arenas.alloc_module(graph_root);
let mut module_map = NodeMap();
module_map.insert(CRATE_NODE_ID, graph_root);
Resolver {
session: session,
ast_map: ast_map,
// The outermost module has def ID 0; this is not reflected in the
// AST.
graph_root: graph_root,
trait_item_map: FnvHashMap(),
structs: FnvHashMap(),
unresolved_imports: 0,
current_module: graph_root,
2016-02-26 05:39:33 +00:00
value_ribs: vec![Rib::new(ModuleRibKind(graph_root))],
type_ribs: vec![Rib::new(ModuleRibKind(graph_root))],
label_ribs: Vec::new(),
current_trait_ref: None,
current_self_type: None,
primitive_type_table: PrimitiveTypeTable::new(),
def_map: NodeMap(),
freevars: NodeMap(),
freevars_seen: NodeMap(),
export_map: NodeMap(),
trait_map: NodeMap(),
module_map: module_map,
emit_errors: true,
make_glob_map: make_glob_map == MakeGlobMap::Yes,
2016-03-29 13:14:01 +03:00
glob_map: NodeMap(),
2016-04-19 22:43:10 +09:00
used_imports: HashSet::new(),
used_crates: HashSet::new(),
maybe_unused_trait_imports: NodeSet(),
privacy_errors: Vec::new(),
arenas: arenas,
}
}
fn arenas() -> ResolverArenas<'a> {
ResolverArenas {
modules: arena::TypedArena::new(),
local_modules: RefCell::new(Vec::new()),
name_bindings: arena::TypedArena::new(),
2016-02-15 02:22:59 +00:00
import_directives: arena::TypedArena::new(),
name_resolutions: arena::TypedArena::new(),
}
}
2016-04-26 04:20:50 +00:00
fn new_module(&self, parent_link: ParentLink<'a>, def: Option<Def>, external: bool)
-> Module<'a> {
self.arenas.alloc_module(ModuleS::new(parent_link, def, external, self.arenas))
}
2016-04-26 04:20:50 +00:00
fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def, local_node_id: NodeId)
-> Module<'a> {
2016-04-26 04:20:50 +00:00
let mut module = ModuleS::new(parent_link, Some(def), false, self.arenas);
module.extern_crate_id = Some(local_node_id);
self.arenas.modules.alloc(module)
}
fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec<Rib<'a>> {
match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs }
}
#[inline]
2016-04-19 22:43:10 +09:00
fn record_use(&mut self, name: Name, binding: &'a NameBinding<'a>) {
// track extern crates for unused_extern_crate lint
if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) {
self.used_crates.insert(krate);
}
2016-04-17 01:57:09 +00:00
let (directive, privacy_error) = match binding.kind {
NameBindingKind::Import { directive, ref privacy_error, .. } =>
(directive, privacy_error),
_ => return,
};
if let Some(error) = privacy_error.as_ref() {
self.privacy_errors.push((**error).clone());
}
if !self.make_glob_map {
return;
}
2016-04-17 01:57:09 +00:00
if self.glob_map.contains_key(&directive.id) {
self.glob_map.get_mut(&directive.id).unwrap().insert(name);
return;
}
2016-03-29 13:14:01 +03:00
let mut new_set = FnvHashSet();
new_set.insert(name);
2016-04-17 01:57:09 +00:00
self.glob_map.insert(directive.id, new_set);
}
/// Resolves the given module path from the given root `module_`.
2013-10-02 14:33:01 +02:00
fn resolve_module_path_from_root(&mut self,
module_: Module<'a>,
module_path: &[Name],
index: usize,
2016-02-25 03:36:17 +00:00
span: Span)
-> ResolveResult<Module<'a>> {
fn search_parent_externals(needle: Name, module: Module) -> Option<Module> {
match module.resolve_name(needle, TypeNS, false) {
Success(binding) if binding.is_extern_crate() => Some(module),
_ => match module.parent_link {
ModuleParentLink(ref parent, _) => {
search_parent_externals(needle, parent)
}
2015-10-26 20:31:11 +01:00
_ => None,
},
}
}
let mut search_module = module_;
let mut index = index;
2013-03-07 18:37:14 -05:00
let module_path_len = module_path.len();
// Resolve the module part of the path. This does not involve looking
// upward though scope chains; we simply resolve names directly in
// modules as we go.
while index < module_path_len {
2013-03-07 18:37:14 -05:00
let name = module_path[index];
2016-01-31 04:25:49 +00:00
match self.resolve_name_in_module(search_module, name, TypeNS, false, true) {
Failed(None) => {
let segment_name = name.as_str();
let module_name = module_to_string(search_module);
let mut span = span;
2016-01-29 23:34:58 +00:00
let msg = if "???" == &module_name {
2015-02-04 00:48:39 +01:00
span.hi = span.lo + Pos::from_usize(segment_name.len());
2015-10-26 20:31:11 +01:00
match search_parent_externals(name, &self.current_module) {
Some(module) => {
let path_str = names_to_string(module_path);
2016-02-09 21:27:42 +01:00
let target_mod_str = module_to_string(&module);
let current_mod_str = module_to_string(&self.current_module);
let prefix = if target_mod_str == current_mod_str {
"self::".to_string()
} else {
format!("{}::", target_mod_str)
};
format!("Did you mean `{}{}`?", prefix, path_str)
2015-10-26 20:31:11 +01:00
}
None => format!("Maybe a missing `extern crate {}`?", segment_name),
}
} else {
2015-10-26 20:31:11 +01:00
format!("Could not find `{}` in `{}`", segment_name, module_name)
};
return Failed(Some((span, msg)));
}
Failed(err) => return Failed(err),
2012-08-03 19:59:04 -07:00
Indeterminate => {
2015-10-26 20:31:11 +01:00
debug!("(resolving module path for import) module resolution is \
indeterminate: {}",
name);
2012-08-01 17:30:05 -07:00
return Indeterminate;
}
Success(binding) => {
// Check to see whether there are type bindings, and, if
// so, whether there is a module within.
2016-02-07 21:04:01 +00:00
if let Some(module_def) = binding.module() {
self.check_privacy(name, binding, span);
search_module = module_def;
} else {
let msg = format!("Not a module `{}`", name);
return Failed(Some((span, msg)));
}
}
}
index += 1;
}
2016-02-25 03:36:17 +00:00
return Success(search_module);
}
/// Attempts to resolve the module part of an import directive or path
/// rooted at the given module.
2013-10-02 14:33:01 +02:00
fn resolve_module_path(&mut self,
module_path: &[Name],
Extract privacy checking from name resolution This commit is the culmination of my recent effort to refine Rust's notion of privacy and visibility among crates. The major goals of this commit were to remove privacy checking from resolve for the sake of sane error messages, and to attempt a much more rigid and well-tested implementation of visibility throughout rust. The implemented rules for name visibility are: 1. Everything pub from the root namespace is visible to anyone 2. You may access any private item of your ancestors. "Accessing a private item" depends on what the item is, so for a function this means that you can call it, but for a module it means that you can look inside of it. Once you look inside a private module, any accessed item must be "pub from the root" where the new root is the private module that you looked into. These rules required some more analysis results to get propagated from trans to privacy in the form of a few hash tables. I added a new test in which my goal was to showcase all of the privacy nuances of the language, and I hope to place any new bugs into this file to prevent regressions. Overall, I was unable to completely remove the notion of privacy from resolve. One use of privacy is for dealing with glob imports. Essentially a glob import can only import *public* items from the destination, and because this must be done at namespace resolution time, resolve must maintain the notion of "what items are public in a module". There are some sad approximations of privacy, but I unfortunately can't see clear methods to extract them outside. The other use case of privacy in resolve now is one that must stick around regardless of glob imports. When dealing with privacy, checking a private path needs to know "what the last private thing was" when looking at a path. Resolve is the only compiler pass which knows the answer to this question, so it maintains the answer on a per-path resolution basis (works similarly to the def_map generated). Closes #8215
2013-10-05 14:37:39 -07:00
use_lexical_scope: UseLexicalScopeFlag,
2016-01-26 09:52:33 +00:00
span: Span)
2016-02-25 03:36:17 +00:00
-> ResolveResult<Module<'a>> {
2016-01-16 11:41:19 +00:00
if module_path.len() == 0 {
2016-02-25 03:36:17 +00:00
return Success(self.graph_root) // Use the crate root
2016-01-16 11:41:19 +00:00
}
debug!("(resolving module path for import) processing `{}` rooted at `{}`",
names_to_string(module_path),
2016-03-08 21:44:19 +00:00
module_to_string(self.current_module));
// Resolve the module prefix, if any.
let module_prefix_result = self.resolve_module_prefix(module_path, span);
2013-04-12 01:15:30 -04:00
let search_module;
let start_index;
match module_prefix_result {
Failed(err) => return Failed(err),
2012-08-03 19:59:04 -07:00
Indeterminate => {
2015-10-26 20:31:11 +01:00
debug!("(resolving module path for import) indeterminate; bailing");
2012-08-01 17:30:05 -07:00
return Indeterminate;
}
Success(NoPrefixFound) => {
// There was no prefix, so we're considering the first element
// of the path. How we handle this depends on whether we were
// instructed to use lexical scope or not.
match use_lexical_scope {
DontUseLexicalScope => {
// This is a crate-relative path. We will start the
// resolution process at index zero.
search_module = self.graph_root;
start_index = 0;
}
UseLexicalScope => {
// This is not a crate-relative path. We resolve the
// first component of the path in the current lexical
// scope and then proceed to resolve below that.
let ident = hir::Ident::from_name(module_path[0]);
match self.resolve_ident_in_lexical_scope(ident, TypeNS, true)
.and_then(LexicalScopeBinding::module) {
None => return Failed(None),
Some(containing_module) => {
search_module = containing_module;
start_index = 1;
}
}
}
}
}
2014-04-14 11:30:59 +03:00
Success(PrefixFound(ref containing_module, index)) => {
search_module = containing_module;
start_index = index;
}
}
self.resolve_module_path_from_root(search_module,
module_path,
start_index,
2016-02-25 03:36:17 +00:00
span)
}
/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
/// More specifically, we proceed up the hierarchy of scopes and return the binding for
/// `ident` in the first scope that defines it (or None if no scopes define it).
///
/// A block's items are above its local variables in the scope hierarchy, regardless of where
/// the items are defined in the block. For example,
/// ```rust
/// fn f() {
/// g(); // Since there are no local variables in scope yet, this resolves to the item.
/// let g = || {};
/// fn g() {}
/// g(); // This resolves to the local variable `g` since it shadows the item.
/// }
/// ```
///
/// Invariant: This must only be called during main resolution, not during
/// import resolution.
fn resolve_ident_in_lexical_scope(&mut self,
ident: hir::Ident,
ns: Namespace,
record_used: bool)
-> Option<LexicalScopeBinding<'a>> {
let name = match ns { ValueNS => ident.name, TypeNS => ident.unhygienic_name };
// Walk backwards up the ribs in scope.
for i in (0 .. self.get_ribs(ns).len()).rev() {
if let Some(def) = self.get_ribs(ns)[i].bindings.get(&name).cloned() {
// The ident resolves to a type parameter or local variable.
return Some(LexicalScopeBinding::LocalDef(LocalDef {
ribs: Some((ns, i)),
def: def,
}));
}
if let ModuleRibKind(module) = self.get_ribs(ns)[i].kind {
let name = ident.unhygienic_name;
let item = self.resolve_name_in_module(module, name, ns, true, record_used);
if let Success(binding) = item {
// The ident resolves to an item.
return Some(LexicalScopeBinding::Item(binding));
}
2016-03-08 21:44:19 +00:00
// We can only see through anonymous modules
if module.def.is_some() { return None; }
}
}
2016-03-08 21:44:19 +00:00
None
}
/// Returns the nearest normal module parent of the given module.
fn get_nearest_normal_module_parent(&self, module_: Module<'a>) -> Option<Module<'a>> {
let mut module_ = module_;
loop {
match module_.parent_link {
NoParentLink => return None,
ModuleParentLink(new_module, _) |
BlockParentLink(new_module, _) => {
let new_module = new_module;
if new_module.is_normal() {
return Some(new_module);
}
module_ = new_module;
}
}
}
}
/// Returns the nearest normal module parent of the given module, or the
/// module itself if it is a normal module.
fn get_nearest_normal_module_parent_or_self(&self, module_: Module<'a>) -> Module<'a> {
if module_.is_normal() {
return module_;
}
match self.get_nearest_normal_module_parent(module_) {
None => module_,
Some(new_module) => new_module,
}
}
/// Resolves a "module prefix". A module prefix is one or both of (a) `self::`;
/// (b) some chain of `super::`.
/// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) *
fn resolve_module_prefix(&mut self, module_path: &[Name], span: Span)
-> ResolveResult<ModulePrefixResult<'a>> {
// Start at the current module if we see `self` or `super`, or at the
// top of the crate otherwise.
let mut i = match &*module_path[0].as_str() {
"self" => 1,
"super" => 0,
_ => return Success(NoPrefixFound),
};
2016-03-08 21:44:19 +00:00
let module_ = self.current_module;
let mut containing_module = self.get_nearest_normal_module_parent_or_self(module_);
// Now loop through all the `super`s we find.
while i < module_path.len() && "super" == module_path[i].as_str() {
debug!("(resolving module prefix) resolving `super` at {}",
2016-02-09 21:27:42 +01:00
module_to_string(&containing_module));
match self.get_nearest_normal_module_parent(containing_module) {
None => {
let msg = "There are too many initial `super`s.".into();
return Failed(Some((span, msg)));
}
Some(new_module) => {
containing_module = new_module;
i += 1;
}
}
}
debug!("(resolving module prefix) finished resolving prefix at {}",
2016-02-09 21:27:42 +01:00
module_to_string(&containing_module));
return Success(PrefixFound(containing_module, i));
}
/// Attempts to resolve the supplied name in the given module for the
2016-02-07 21:04:01 +00:00
/// given namespace. If successful, returns the binding corresponding to
/// the name.
2013-10-02 14:33:01 +02:00
fn resolve_name_in_module(&mut self,
module: Module<'a>,
name: Name,
Extract privacy checking from name resolution This commit is the culmination of my recent effort to refine Rust's notion of privacy and visibility among crates. The major goals of this commit were to remove privacy checking from resolve for the sake of sane error messages, and to attempt a much more rigid and well-tested implementation of visibility throughout rust. The implemented rules for name visibility are: 1. Everything pub from the root namespace is visible to anyone 2. You may access any private item of your ancestors. "Accessing a private item" depends on what the item is, so for a function this means that you can call it, but for a module it means that you can look inside of it. Once you look inside a private module, any accessed item must be "pub from the root" where the new root is the private module that you looked into. These rules required some more analysis results to get propagated from trans to privacy in the form of a few hash tables. I added a new test in which my goal was to showcase all of the privacy nuances of the language, and I hope to place any new bugs into this file to prevent regressions. Overall, I was unable to completely remove the notion of privacy from resolve. One use of privacy is for dealing with glob imports. Essentially a glob import can only import *public* items from the destination, and because this must be done at namespace resolution time, resolve must maintain the notion of "what items are public in a module". There are some sad approximations of privacy, but I unfortunately can't see clear methods to extract them outside. The other use case of privacy in resolve now is one that must stick around regardless of glob imports. When dealing with privacy, checking a private path needs to know "what the last private thing was" when looking at a path. Resolve is the only compiler pass which knows the answer to this question, so it maintains the answer on a per-path resolution basis (works similarly to the def_map generated). Closes #8215
2013-10-05 14:37:39 -07:00
namespace: Namespace,
use_lexical_scope: bool,
2016-01-31 04:25:49 +00:00
record_used: bool)
-> ResolveResult<&'a NameBinding<'a>> {
debug!("(resolving name in module) resolving `{}` in `{}`", name, module_to_string(module));
self.populate_module_if_necessary(module);
match use_lexical_scope {
true => module.resolve_name_in_lexical_scope(name, namespace)
.map(Success).unwrap_or(Failed(None)),
false => module.resolve_name(name, namespace, false),
}.and_then(|binding| {
if record_used {
2016-04-19 22:43:10 +09:00
if let NameBindingKind::Import { directive, .. } = binding.kind {
self.used_imports.insert((directive.id, namespace));
}
self.record_use(name, binding);
}
Success(binding)
})
}
// AST resolution
//
// We maintain a list of value ribs and type ribs.
//
// Simultaneously, we keep track of the current position in the module
// graph in the `current_module` pointer. When we go to resolve a name in
// the value or type namespaces, we first look through all the ribs and
// then query the module graph. When we resolve a name in the module
// namespace, we can skip all the ribs (since nested modules are not
// allowed within blocks in Rust) and jump straight to the current module
// graph node.
//
// Named implementations are handled separately. When we find a method
// call, we consult the module node to find all of the implementations in
// scope. This information is lazily cached in the module node. We then
// generate a fake "implementation scope" containing all the
// implementations thus found, for compatibility with old resolve pass.
fn with_scope<F>(&mut self, id: NodeId, f: F)
2015-10-26 20:31:11 +01:00
where F: FnOnce(&mut Resolver)
2014-12-08 20:26:43 -05:00
{
let module = self.module_map.get(&id).cloned(); // clones a reference
if let Some(module) = module {
// Move down in the graph.
let orig_module = ::std::mem::replace(&mut self.current_module, module);
self.value_ribs.push(Rib::new(ModuleRibKind(module)));
self.type_ribs.push(Rib::new(ModuleRibKind(module)));
f(self);
self.current_module = orig_module;
self.value_ribs.pop();
self.type_ribs.pop();
} else {
f(self);
}
}
2014-12-27 21:47:42 +09:00
/// Searches the current set of local scopes for labels.
/// Stops after meeting a closure.
fn search_label(&self, name: Name) -> Option<Def> {
for rib in self.label_ribs.iter().rev() {
match rib.kind {
NormalRibKind => {
// Continue
}
_ => {
// Do not resolve labels across function boundary
2015-10-26 20:31:11 +01:00
return None;
}
}
let result = rib.bindings.get(&name).cloned();
2014-12-27 21:47:42 +09:00
if result.is_some() {
2015-10-26 20:31:11 +01:00
return result;
}
}
None
}
2015-07-31 00:04:06 -07:00
fn resolve_crate(&mut self, krate: &hir::Crate) {
debug!("(resolving crate) starting");
self.current_module = self.graph_root;
intravisit::walk_crate(self, krate);
}
fn resolve_item(&mut self, item: &Item) {
2015-09-20 04:50:30 +03:00
let name = item.name;
2015-10-26 20:31:11 +01:00
debug!("(resolving item) resolving {}", name);
match item.node {
ItemEnum(_, ref generics) |
ItemTy(_, ref generics) |
ItemStruct(_, ref generics) => {
2015-10-26 20:31:11 +01:00
self.with_type_parameter_rib(HasTypeParameters(generics, TypeSpace, ItemRibKind),
|this| intravisit::walk_item(this, item));
}
ItemFn(_, _, _, _, ref generics, _) => {
2015-10-26 20:31:11 +01:00
self.with_type_parameter_rib(HasTypeParameters(generics, FnSpace, ItemRibKind),
|this| intravisit::walk_item(this, item));
}
2015-02-07 14:24:34 +01:00
ItemDefaultImpl(_, ref trait_ref) => {
self.with_optional_trait_ref(Some(trait_ref), |_, _| {});
}
2015-10-26 20:31:11 +01:00
ItemImpl(_, _, ref generics, ref opt_trait_ref, ref self_type, ref impl_items) => {
self.resolve_implementation(generics,
opt_trait_ref,
2016-02-09 21:27:42 +01:00
&self_type,
item.id,
impl_items);
}
ItemTrait(_, ref generics, ref bounds, ref trait_items) => {
// Create a new rib for the trait-wide type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
ItemRibKind),
|this| {
let local_def_id = this.ast_map.local_def_id(item.id);
this.with_self_rib(Def::SelfTy(Some(local_def_id), None), |this| {
this.visit_generics(generics);
walk_list!(this, visit_ty_param_bound, bounds);
for trait_item in trait_items {
match trait_item.node {
2015-07-31 00:04:06 -07:00
hir::ConstTraitItem(_, ref default) => {
// Only impose the restrictions of
// ConstRibKind if there's an actual constant
// expression in a provided default.
if default.is_some() {
this.with_constant_rib(|this| {
intravisit::walk_trait_item(this, trait_item)
});
} else {
intravisit::walk_trait_item(this, trait_item)
}
}
2015-07-31 00:04:06 -07:00
hir::MethodTraitItem(ref sig, _) => {
let type_parameters =
HasTypeParameters(&sig.generics,
FnSpace,
MethodRibKind);
this.with_type_parameter_rib(type_parameters, |this| {
intravisit::walk_trait_item(this, trait_item)
});
}
2015-07-31 00:04:06 -07:00
hir::TypeTraitItem(..) => {
this.with_type_parameter_rib(NoTypeParameters, |this| {
intravisit::walk_trait_item(this, trait_item)
});
}
};
}
});
});
}
ItemMod(_) | ItemForeignMod(_) => {
self.with_scope(item.id, |this| {
intravisit::walk_item(this, item);
});
}
rustc: Add `const` globals to the language This change is an implementation of [RFC 69][rfc] which adds a third kind of global to the language, `const`. This global is most similar to what the old `static` was, and if you're unsure about what to use then you should use a `const`. The semantics of these three kinds of globals are: * A `const` does not represent a memory location, but only a value. Constants are translated as rvalues, which means that their values are directly inlined at usage location (similar to a #define in C/C++). Constant values are, well, constant, and can not be modified. Any "modification" is actually a modification to a local value on the stack rather than the actual constant itself. Almost all values are allowed inside constants, whether they have interior mutability or not. There are a few minor restrictions listed in the RFC, but they should in general not come up too often. * A `static` now always represents a memory location (unconditionally). Any references to the same `static` are actually a reference to the same memory location. Only values whose types ascribe to `Sync` are allowed in a `static`. This restriction is in place because many threads may access a `static` concurrently. Lifting this restriction (and allowing unsafe access) is a future extension not implemented at this time. * A `static mut` continues to always represent a memory location. All references to a `static mut` continue to be `unsafe`. This is a large breaking change, and many programs will need to be updated accordingly. A summary of the breaking changes is: * Statics may no longer be used in patterns. Statics now always represent a memory location, which can sometimes be modified. To fix code, repurpose the matched-on-`static` to a `const`. static FOO: uint = 4; match n { FOO => { /* ... */ } _ => { /* ... */ } } change this code to: const FOO: uint = 4; match n { FOO => { /* ... */ } _ => { /* ... */ } } * Statics may no longer refer to other statics by value. Due to statics being able to change at runtime, allowing them to reference one another could possibly lead to confusing semantics. If you are in this situation, use a constant initializer instead. Note, however, that statics may reference other statics by address, however. * Statics may no longer be used in constant expressions, such as array lengths. This is due to the same restrictions as listed above. Use a `const` instead. [breaking-change] [rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 08:17:01 -07:00
ItemConst(..) | ItemStatic(..) => {
self.with_constant_rib(|this| {
intravisit::walk_item(this, item);
});
}
2015-02-08 19:29:47 +03:00
ItemUse(ref view_path) => {
match view_path.node {
hir::ViewPathList(ref prefix, ref items) => {
// Resolve prefix of an import with empty braces (issue #28388)
if items.is_empty() && !prefix.segments.is_empty() {
match self.resolve_crate_relative_path(prefix.span,
&prefix.segments,
TypeNS) {
Ok(binding) => {
let def = binding.def().unwrap();
self.record_def(item.id, PathResolution::new(def, 0));
}
2016-04-07 00:42:29 +00:00
Err(true) => self.record_def(item.id, err_path_resolution()),
Err(false) => {
resolve_error(self,
prefix.span,
ResolutionError::FailedToResolve(
&path_names_to_string(prefix, 0)));
2015-12-11 20:59:11 +13:00
self.record_def(item.id, err_path_resolution());
}
}
}
}
_ => {}
2015-02-08 19:29:47 +03:00
}
}
2015-07-31 00:04:06 -07:00
ItemExternCrate(_) => {
2013-12-25 11:10:33 -07:00
// do nothing, these are just around to be encoded
}
}
}
fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<'a, 'b>, f: F)
2015-10-26 20:31:11 +01:00
where F: FnOnce(&mut Resolver)
2014-12-08 20:26:43 -05:00
{
2012-08-06 12:34:08 -07:00
match type_parameters {
HasTypeParameters(generics, space, rib_kind) => {
let mut function_type_rib = Rib::new(rib_kind);
let mut seen_bindings = HashSet::new();
for (index, type_parameter) in generics.ty_params.iter().enumerate() {
let name = type_parameter.name;
debug!("with_type_parameter_rib: {}", type_parameter.id);
if seen_bindings.contains(&name) {
resolve_error(self,
type_parameter.span,
2015-10-26 20:31:11 +01:00
ResolutionError::NameAlreadyUsedInTypeParameterList(name));
}
seen_bindings.insert(name);
// plain insert (no renaming)
let def_id = self.ast_map.local_def_id(type_parameter.id);
let def = Def::TyParam(space, index as u32, def_id, name);
function_type_rib.bindings.insert(name, def);
}
self.type_ribs.push(function_type_rib);
}
2012-08-03 19:59:04 -07:00
NoTypeParameters => {
// Nothing to do.
}
}
f(self);
2016-04-23 21:20:17 +00:00
if let HasTypeParameters(..) = type_parameters {
self.type_ribs.pop();
}
}
2015-10-26 20:31:11 +01:00
fn with_label_rib<F>(&mut self, f: F)
where F: FnOnce(&mut Resolver)
2014-12-08 20:26:43 -05:00
{
self.label_ribs.push(Rib::new(NormalRibKind));
f(self);
2016-04-23 21:20:17 +00:00
self.label_ribs.pop();
}
2013-02-21 11:08:50 -08:00
2015-10-26 20:31:11 +01:00
fn with_constant_rib<F>(&mut self, f: F)
where F: FnOnce(&mut Resolver)
2014-12-08 20:26:43 -05:00
{
self.value_ribs.push(Rib::new(ConstantItemRibKind));
self.type_ribs.push(Rib::new(ConstantItemRibKind));
f(self);
2016-04-23 21:20:17 +00:00
self.type_ribs.pop();
self.value_ribs.pop();
}
fn resolve_function(&mut self, rib_kind: RibKind<'a>, declaration: &FnDecl, block: &Block) {
// Create a value rib for the function.
self.value_ribs.push(Rib::new(rib_kind));
// Create a label rib for the function.
self.label_ribs.push(Rib::new(rib_kind));
// Add each argument to the rib.
let mut bindings_list = HashMap::new();
for argument in &declaration.inputs {
2016-02-09 21:27:42 +01:00
self.resolve_pattern(&argument.pat, ArgumentIrrefutableMode, &mut bindings_list);
2016-02-09 21:27:42 +01:00
self.visit_ty(&argument.ty);
debug!("(resolving function) recorded argument");
}
intravisit::walk_fn_ret_ty(self, &declaration.output);
// Resolve the function body.
self.visit_block(block);
debug!("(resolving function) leaving function");
2016-04-23 21:20:17 +00:00
self.label_ribs.pop();
self.value_ribs.pop();
}
2013-10-02 14:33:01 +02:00
fn resolve_trait_reference(&mut self,
id: NodeId,
2015-01-30 10:09:44 +02:00
trait_path: &Path,
path_depth: usize)
-> Result<PathResolution, ()> {
2016-04-07 00:42:29 +00:00
self.resolve_path(id, trait_path, path_depth, TypeNS).and_then(|path_res| {
if let Def::Trait(_) = path_res.base_def {
debug!("(resolving trait) found trait def: {:?}", path_res);
Ok(path_res)
} else {
2015-12-21 10:00:43 +13:00
let mut err =
resolve_struct_error(self,
trait_path.span,
2016-02-09 21:27:42 +01:00
ResolutionError::IsNotATrait(&path_names_to_string(trait_path,
2015-12-21 10:00:43 +13:00
path_depth)));
// If it's a typedef, give a note
if let Def::TyAlias(..) = path_res.base_def {
2016-04-29 18:08:02 -04:00
err.note("`type` aliases cannot be used for traits");
let definition_site = {
let segments = &trait_path.segments;
if trait_path.global {
self.resolve_crate_relative_path(trait_path.span, segments, TypeNS)
} else {
self.resolve_module_relative_path(trait_path.span, segments, TypeNS)
}.map(|binding| binding.span).unwrap_or(codemap::DUMMY_SP)
};
if definition_site != codemap::DUMMY_SP {
err.span_note(definition_site, "type defined here");
}
}
2015-12-23 19:27:20 +13:00
err.emit();
2016-04-07 00:42:29 +00:00
Err(true)
}
2016-04-07 00:42:29 +00:00
}).map_err(|error_reported| {
if error_reported { return }
// find possible candidates
let trait_name = trait_path.segments.last().unwrap().identifier.name;
let candidates =
self.lookup_candidates(
trait_name,
TypeNS,
|def| match def {
Def::Trait(_) => true,
_ => false,
},
);
// create error object
let name = &path_names_to_string(trait_path, path_depth);
let error =
ResolutionError::UndeclaredTraitName(
name,
candidates,
);
resolve_error(self, trait_path.span, error);
2016-04-07 00:42:29 +00:00
})
}
fn resolve_generics(&mut self, generics: &Generics) {
for predicate in &generics.where_clause.predicates {
match predicate {
2015-07-31 00:04:06 -07:00
&hir::WherePredicate::BoundPredicate(_) |
&hir::WherePredicate::RegionPredicate(_) => {}
&hir::WherePredicate::EqPredicate(ref eq_pred) => {
2016-04-07 00:42:29 +00:00
self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS).and_then(|path_res| {
if let PathResolution { base_def: Def::TyParam(..), .. } = path_res {
Ok(self.record_def(eq_pred.id, path_res))
} else {
Err(false)
}
}).map_err(|error_reported| {
2015-12-11 20:59:11 +13:00
self.record_def(eq_pred.id, err_path_resolution());
2016-04-07 00:42:29 +00:00
if error_reported { return }
2016-04-07 04:13:34 +00:00
let error_variant = ResolutionError::UndeclaredAssociatedType;
resolve_error(self, eq_pred.span, error_variant);
2016-04-07 00:42:29 +00:00
}).unwrap_or(());
}
}
}
intravisit::walk_generics(self, generics);
}
fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
where F: FnOnce(&mut Resolver) -> T
2014-12-08 20:26:43 -05:00
{
// Handle nested impls (inside fn bodies)
let previous_value = replace(&mut self.current_self_type, Some(self_type.clone()));
let result = f(self);
self.current_self_type = previous_value;
result
}
2015-10-26 20:31:11 +01:00
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
where F: FnOnce(&mut Resolver, Option<DefId>) -> T
2014-12-08 20:26:43 -05:00
{
let mut new_val = None;
let mut new_id = None;
2015-02-24 08:28:11 +02:00
if let Some(trait_ref) = opt_trait_ref {
if let Ok(path_res) = self.resolve_trait_reference(trait_ref.ref_id,
2015-10-26 20:31:11 +01:00
&trait_ref.path,
0) {
assert!(path_res.depth == 0);
self.record_def(trait_ref.ref_id, path_res);
new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
new_id = Some(path_res.base_def.def_id());
2015-12-11 20:59:11 +13:00
} else {
self.record_def(trait_ref.ref_id, err_path_resolution());
}
intravisit::walk_trait_ref(self, trait_ref);
}
let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
let result = f(self, new_id);
self.current_trait_ref = original_trait_ref;
result
}
fn with_self_rib<F>(&mut self, self_def: Def, f: F)
where F: FnOnce(&mut Resolver)
{
let mut self_type_rib = Rib::new(NormalRibKind);
// plain insert (no renaming, types are not currently hygienic....)
self_type_rib.bindings.insert(keywords::SelfType.name(), self_def);
self.type_ribs.push(self_type_rib);
f(self);
2016-04-23 21:20:17 +00:00
self.type_ribs.pop();
}
2013-10-02 14:33:01 +02:00
fn resolve_implementation(&mut self,
generics: &Generics,
opt_trait_reference: &Option<TraitRef>,
self_type: &Ty,
item_id: NodeId,
impl_items: &[ImplItem]) {
// If applicable, create a rib for the type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
ItemRibKind),
|this| {
// Resolve the type parameters.
this.visit_generics(generics);
// Resolve the trait reference, if necessary.
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
// Resolve the self type.
this.visit_ty(self_type);
this.with_self_rib(Def::SelfTy(trait_id, Some((item_id, self_type.id))), |this| {
this.with_current_self_type(self_type, |this| {
for impl_item in impl_items {
this.resolve_visibility(&impl_item.vis);
match impl_item.node {
2015-11-12 15:57:51 +01:00
hir::ImplItemKind::Const(..) => {
// If this is a trait impl, ensure the const
// exists in trait
2015-09-20 04:50:30 +03:00
this.check_trait_item(impl_item.name,
impl_item.span,
|n, s| ResolutionError::ConstNotMemberOfTrait(n, s));
this.with_constant_rib(|this| {
intravisit::walk_impl_item(this, impl_item);
});
}
2015-11-12 15:57:51 +01:00
hir::ImplItemKind::Method(ref sig, _) => {
// If this is a trait impl, ensure the method
// exists in trait
2015-09-20 04:50:30 +03:00
this.check_trait_item(impl_item.name,
impl_item.span,
|n, s| ResolutionError::MethodNotMemberOfTrait(n, s));
// We also need a new scope for the method-
// specific type parameters.
let type_parameters =
HasTypeParameters(&sig.generics,
FnSpace,
MethodRibKind);
this.with_type_parameter_rib(type_parameters, |this| {
intravisit::walk_impl_item(this, impl_item);
});
}
2015-11-12 15:57:51 +01:00
hir::ImplItemKind::Type(ref ty) => {
// If this is a trait impl, ensure the type
// exists in trait
2015-09-20 04:50:30 +03:00
this.check_trait_item(impl_item.name,
impl_item.span,
|n, s| ResolutionError::TypeNotMemberOfTrait(n, s));
this.visit_ty(ty);
}
}
}
});
});
});
});
}
fn check_trait_item<F>(&self, name: Name, span: Span, err: F)
2015-10-26 20:31:11 +01:00
where F: FnOnce(Name, &str) -> ResolutionError
{
// If there is a TraitRef in scope for an impl, then the method must be in the
// trait.
2015-01-31 12:20:46 -05:00
if let Some((did, ref trait_ref)) = self.current_trait_ref {
if !self.trait_item_map.contains_key(&(name, did)) {
let path_str = path_names_to_string(&trait_ref.path, 0);
2016-02-09 21:27:42 +01:00
resolve_error(self, span, err(name, &path_str));
}
}
}
2014-01-06 14:00:46 +02:00
fn resolve_local(&mut self, local: &Local) {
// Resolve the type.
walk_list!(self, visit_ty, &local.ty);
// Resolve the initializer.
walk_list!(self, visit_expr, &local.init);
// Resolve the pattern.
2016-02-09 21:27:42 +01:00
self.resolve_pattern(&local.pat, LocalIrrefutableMode, &mut HashMap::new());
}
2013-09-05 14:15:00 -07:00
// build a map from pattern identifiers to binding-info's.
// this is done hygienically. This could arise for a macro
// that expands into an or-pattern where one 'x' was from the
// user and one 'x' came from the macro.
2014-04-14 11:30:59 +03:00
fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
let mut result = HashMap::new();
let def_map = RefCell::new(::std::mem::replace(&mut self.def_map, NodeMap()));
pat_bindings(&def_map, pat, |binding_mode, _id, sp, path1| {
let name = path1.node;
2015-10-26 20:31:11 +01:00
result.insert(name,
BindingInfo {
span: sp,
binding_mode: binding_mode,
});
});
self.def_map = def_map.into_inner();
return result;
}
2013-09-05 14:15:00 -07:00
// check that all of the arms in an or-pattern have exactly the
// same set of bindings, with the same binding modes for each.
2013-10-02 14:33:01 +02:00
fn check_consistent_bindings(&mut self, arm: &Arm) {
if arm.pats.is_empty() {
2015-10-26 20:31:11 +01:00
return;
}
2016-02-09 21:27:42 +01:00
let map_0 = self.binding_mode_map(&arm.pats[0]);
for (i, p) in arm.pats.iter().enumerate() {
2016-02-09 21:27:42 +01:00
let map_i = self.binding_mode_map(&p);
2015-01-31 12:20:46 -05:00
for (&key, &binding_0) in &map_0 {
2014-11-06 12:25:16 -05:00
match map_i.get(&key) {
2015-10-26 20:31:11 +01:00
None => {
resolve_error(self,
2015-10-26 20:31:11 +01:00
p.span,
ResolutionError::VariableNotBoundInPattern(key, i + 1));
}
Some(binding_i) => {
if binding_0.binding_mode != binding_i.binding_mode {
resolve_error(self,
binding_i.span,
ResolutionError::VariableBoundWithDifferentMode(key,
i + 1));
}
}
}
}
2015-01-31 12:20:46 -05:00
for (&key, &binding) in &map_i {
if !map_0.contains_key(&key) {
resolve_error(self,
binding.span,
2015-10-26 20:31:11 +01:00
ResolutionError::VariableNotBoundInParentPattern(key, i + 1));
}
}
}
}
2013-10-02 14:33:01 +02:00
fn resolve_arm(&mut self, arm: &Arm) {
self.value_ribs.push(Rib::new(NormalRibKind));
let mut bindings_list = HashMap::new();
2015-01-31 12:20:46 -05:00
for pattern in &arm.pats {
2016-02-09 21:27:42 +01:00
self.resolve_pattern(&pattern, RefutableMode, &mut bindings_list);
}
// This has to happen *after* we determine which
// pat_idents are variants
self.check_consistent_bindings(arm);
walk_list!(self, visit_expr, &arm.guard);
2016-02-09 21:27:42 +01:00
self.visit_expr(&arm.body);
2016-04-23 21:20:17 +00:00
self.value_ribs.pop();
}
2014-01-06 14:00:46 +02:00
fn resolve_block(&mut self, block: &Block) {
debug!("(resolving block) entering block");
// Move down in the graph, if there's an anonymous module rooted here.
let orig_module = self.current_module;
let anonymous_module = self.module_map.get(&block.id).cloned(); // clones a reference
if let Some(anonymous_module) = anonymous_module {
debug!("(resolving block) found anonymous module, moving down");
self.value_ribs.push(Rib::new(ModuleRibKind(anonymous_module)));
self.type_ribs.push(Rib::new(ModuleRibKind(anonymous_module)));
self.current_module = anonymous_module;
} else {
self.value_ribs.push(Rib::new(NormalRibKind));
}
// Descend into the block.
intravisit::walk_block(self, block);
// Move back up.
2016-04-23 21:20:17 +00:00
self.current_module = orig_module;
self.value_ribs.pop();
if let Some(_) = anonymous_module {
self.type_ribs.pop();
}
debug!("(resolving block) leaving block");
}
2013-10-02 14:33:01 +02:00
fn resolve_type(&mut self, ty: &Ty) {
2012-08-06 12:34:08 -07:00
match ty.node {
TyPath(ref maybe_qself, ref path) => {
2015-10-26 20:31:11 +01:00
let resolution = match self.resolve_possibly_assoc_item(ty.id,
maybe_qself.as_ref(),
path,
2016-03-08 23:28:10 +00:00
TypeNS) {
2015-10-26 20:31:11 +01:00
// `<T>::a::b::c` is resolved by typeck alone.
TypecheckRequired => {
// Resolve embedded types.
intravisit::walk_ty(self, ty);
2015-10-26 20:31:11 +01:00
return;
}
ResolveAttempt(resolution) => resolution,
};
// This is a path in the type namespace. Walk through scopes
// looking for it.
2016-04-07 00:42:29 +00:00
if let Some(def) = resolution {
// Write the result into the def map.
debug!("(resolving type) writing resolution for `{}` (id {}) = {:?}",
path_names_to_string(path, 0), ty.id, def);
self.record_def(ty.id, def);
} else {
self.record_def(ty.id, err_path_resolution());
2016-04-07 00:42:29 +00:00
// Keep reporting some errors even if they're ignored above.
if let Err(true) = self.resolve_path(ty.id, path, 0, TypeNS) {
// `resolve_path` already reported the error
} else {
let kind = if maybe_qself.is_some() {
"associated type"
} else {
"type name"
};
2015-10-26 20:31:11 +01:00
let is_invalid_self_type_name = path.segments.len() > 0 &&
maybe_qself.is_none() &&
path.segments[0].identifier.name ==
keywords::SelfType.name();
2015-07-13 00:31:09 +02:00
if is_invalid_self_type_name {
resolve_error(self,
ty.span,
2015-07-14 19:42:38 +02:00
ResolutionError::SelfUsedOutsideImplOrTrait);
} else {
let segment = path.segments.last();
let segment = segment.expect("missing name in path");
let type_name = segment.identifier.name;
let candidates =
self.lookup_candidates(
type_name,
TypeNS,
|def| match def {
Def::Trait(_) |
Def::Enum(_) |
Def::Struct(_) |
Def::TyAlias(_) => true,
_ => false,
},
);
// create error object
let name = &path_names_to_string(path, 0);
let error =
ResolutionError::UseOfUndeclared(
kind,
name,
candidates,
);
resolve_error(self, ty.span, error);
2015-07-13 00:31:09 +02:00
}
}
}
}
_ => {}
}
// Resolve embedded types.
intravisit::walk_ty(self, ty);
}
2013-10-02 14:33:01 +02:00
fn resolve_pattern(&mut self,
2014-04-14 11:30:59 +03:00
pattern: &Pat,
Extract privacy checking from name resolution This commit is the culmination of my recent effort to refine Rust's notion of privacy and visibility among crates. The major goals of this commit were to remove privacy checking from resolve for the sake of sane error messages, and to attempt a much more rigid and well-tested implementation of visibility throughout rust. The implemented rules for name visibility are: 1. Everything pub from the root namespace is visible to anyone 2. You may access any private item of your ancestors. "Accessing a private item" depends on what the item is, so for a function this means that you can call it, but for a module it means that you can look inside of it. Once you look inside a private module, any accessed item must be "pub from the root" where the new root is the private module that you looked into. These rules required some more analysis results to get propagated from trans to privacy in the form of a few hash tables. I added a new test in which my goal was to showcase all of the privacy nuances of the language, and I hope to place any new bugs into this file to prevent regressions. Overall, I was unable to completely remove the notion of privacy from resolve. One use of privacy is for dealing with glob imports. Essentially a glob import can only import *public* items from the destination, and because this must be done at namespace resolution time, resolve must maintain the notion of "what items are public in a module". There are some sad approximations of privacy, but I unfortunately can't see clear methods to extract them outside. The other use case of privacy in resolve now is one that must stick around regardless of glob imports. When dealing with privacy, checking a private path needs to know "what the last private thing was" when looking at a path. Resolve is the only compiler pass which knows the answer to this question, so it maintains the answer on a per-path resolution basis (works similarly to the def_map generated). Closes #8215
2013-10-05 14:37:39 -07:00
mode: PatternBindingMode,
// Maps idents to the node ID for the (outermost)
// pattern that binds them
bindings_list: &mut HashMap<Name, NodeId>) {
let pat_id = pattern.id;
pattern.walk(|pattern| {
2012-08-06 12:34:08 -07:00
match pattern.node {
2016-02-14 15:25:12 +03:00
PatKind::Ident(binding_mode, ref path1, ref at_rhs) => {
// The meaning of PatKind::Ident with no type parameters
// depends on whether an enum variant or unit-like struct
// with that name is in scope. The probing lookup has to
// be careful not to emit spurious errors. Only matching
// patterns (match) can match nullary variants or
// unit-like structs. For binding patterns (let
// and the LHS of @-patterns), matching such a value is
// simply disallowed (since it's rarely what you want).
let const_ok = mode == RefutableMode && at_rhs.is_none();
let ident = path1.node;
let renamed = ident.name;
match self.resolve_bare_identifier_pattern(ident, pattern.span) {
2016-02-25 03:36:17 +00:00
FoundStructOrEnumVariant(def) if const_ok => {
2015-10-26 20:31:11 +01:00
debug!("(resolving pattern) resolving `{}` to struct or enum variant",
2015-07-08 22:55:22 +02:00
renamed);
2015-10-26 20:31:11 +01:00
self.enforce_default_binding_mode(pattern,
binding_mode,
"an enum variant");
self.record_def(pattern.id,
PathResolution {
base_def: def,
depth: 0,
});
}
2013-11-28 12:22:53 -08:00
FoundStructOrEnumVariant(..) => {
resolve_error(
self,
pattern.span,
2015-07-14 19:42:38 +02:00
ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(
renamed)
);
2015-12-11 20:59:11 +13:00
self.record_def(pattern.id, err_path_resolution());
}
2016-02-25 03:36:17 +00:00
FoundConst(def, _) if const_ok => {
2015-10-26 20:31:11 +01:00
debug!("(resolving pattern) resolving `{}` to constant", renamed);
self.enforce_default_binding_mode(pattern, binding_mode, "a constant");
self.record_def(pattern.id,
PathResolution {
base_def: def,
depth: 0,
});
}
FoundConst(_, name) => {
resolve_error(
self,
pattern.span,
ResolutionError::ConstantForIrrefutableBinding(name)
);
2015-12-11 20:59:11 +13:00
self.record_def(pattern.id, err_path_resolution());
}
BareIdentifierPatternUnresolved => {
2015-10-26 20:31:11 +01:00
debug!("(resolving pattern) binding `{}`", renamed);
let def_id = self.ast_map.local_def_id(pattern.id);
let def = Def::Local(def_id, pattern.id);
// Record the definition so that later passes
// will be able to distinguish variants from
// locals in patterns.
2015-10-26 20:31:11 +01:00
self.record_def(pattern.id,
PathResolution {
base_def: def,
depth: 0,
});
// Add the binding to the local ribs, if it
// doesn't already exist in the bindings list. (We
// must not add it if it's in the bindings list
// because that breaks the assumptions later
// passes make about or-patterns.)
if !bindings_list.contains_key(&renamed) {
let this = &mut *self;
let last_rib = this.value_ribs.last_mut().unwrap();
last_rib.bindings.insert(renamed, def);
bindings_list.insert(renamed, pat_id);
} else if mode == ArgumentIrrefutableMode &&
2015-10-26 20:31:11 +01:00
bindings_list.contains_key(&renamed) {
// Forbid duplicate bindings in the same
// parameter list.
resolve_error(
self,
pattern.span,
2015-07-14 19:42:38 +02:00
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
&ident.name.as_str())
);
2015-10-26 20:31:11 +01:00
} else if bindings_list.get(&renamed) == Some(&pat_id) {
// Then this is a duplicate variable in the
// same disjunction, which is an error.
resolve_error(
self,
pattern.span,
2015-07-14 19:42:38 +02:00
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
&ident.name.as_str())
);
}
// Else, not bound in the same pattern: do
// nothing.
}
}
}
PatKind::TupleStruct(ref path, _) | PatKind::Path(ref path) => {
// This must be an enum variant, struct or const.
2015-10-26 20:31:11 +01:00
let resolution = match self.resolve_possibly_assoc_item(pat_id,
None,
path,
2016-03-08 23:28:10 +00:00
ValueNS) {
2015-10-26 20:31:11 +01:00
// The below shouldn't happen because all
2016-02-14 15:25:12 +03:00
// qualified paths should be in PatKind::QPath.
2015-10-26 20:31:11 +01:00
TypecheckRequired =>
span_bug!(path.span,
"resolve_possibly_assoc_item claimed that a path \
in PatKind::Path or PatKind::TupleStruct \
requires typecheck to resolve, but qualified \
paths should be PatKind::QPath"),
2015-10-26 20:31:11 +01:00
ResolveAttempt(resolution) => resolution,
};
if let Some(path_res) = resolution {
match path_res.base_def {
Def::Struct(..) if path_res.depth == 0 => {
self.record_def(pattern.id, path_res);
}
Def::Variant(..) | Def::Const(..) => {
self.record_def(pattern.id, path_res);
}
Def::Static(..) => {
let segments = &path.segments;
let binding = if path.global {
self.resolve_crate_relative_path(path.span, segments, ValueNS)
} else {
self.resolve_module_relative_path(path.span, segments, ValueNS)
}.unwrap();
let error = ResolutionError::StaticVariableReference(binding);
resolve_error(self, path.span, error);
2015-12-11 20:59:11 +13:00
self.record_def(pattern.id, err_path_resolution());
}
_ => {
// If anything ends up here entirely resolved,
// it's an error. If anything ends up here
// partially resolved, that's OK, because it may
// be a `T::CONST` that typeck will resolve.
if path_res.depth == 0 {
resolve_error(
self,
path.span,
2015-07-14 19:42:38 +02:00
ResolutionError::NotAnEnumVariantStructOrConst(
&path.segments
.last()
.unwrap()
.identifier
.name
.as_str())
);
2015-12-11 20:59:11 +13:00
self.record_def(pattern.id, err_path_resolution());
} else {
2015-10-26 20:31:11 +01:00
let const_name = path.segments
.last()
.unwrap()
.identifier
.name;
let traits = self.get_traits_containing_item(const_name);
self.trait_map.insert(pattern.id, traits);
self.record_def(pattern.id, path_res);
}
}
}
} else if let Err(false) = self.resolve_path(pat_id, &path, 0, ValueNS) {
resolve_error(
self,
path.span,
2015-07-14 19:42:38 +02:00
ResolutionError::UnresolvedEnumVariantStructOrConst(
&path.segments.last().unwrap().identifier.name.as_str())
);
2015-12-11 20:59:11 +13:00
self.record_def(pattern.id, err_path_resolution());
}
intravisit::walk_path(self, path);
}
2016-02-14 15:25:12 +03:00
PatKind::QPath(ref qself, ref path) => {
// Associated constants only.
2015-10-26 20:31:11 +01:00
let resolution = match self.resolve_possibly_assoc_item(pat_id,
Some(qself),
path,
2016-03-08 23:28:10 +00:00
ValueNS) {
2015-10-26 20:31:11 +01:00
TypecheckRequired => {
// All `<T>::CONST` should end up here, and will
// require use of the trait map to resolve
// during typechecking.
let const_name = path.segments
.last()
.unwrap()
.identifier
.name;
let traits = self.get_traits_containing_item(const_name);
self.trait_map.insert(pattern.id, traits);
intravisit::walk_pat(self, pattern);
2015-10-26 20:31:11 +01:00
return true;
}
ResolveAttempt(resolution) => resolution,
};
if let Some(path_res) = resolution {
match path_res.base_def {
// All `<T as Trait>::CONST` should end up here, and
// have the trait already selected.
Def::AssociatedConst(..) => {
self.record_def(pattern.id, path_res);
}
_ => {
resolve_error(
self,
path.span,
2015-07-14 19:42:38 +02:00
ResolutionError::NotAnAssociatedConst(
&path.segments.last().unwrap().identifier.name.as_str()
)
);
2015-12-11 20:59:11 +13:00
self.record_def(pattern.id, err_path_resolution());
}
}
} else {
2015-10-26 20:31:11 +01:00
resolve_error(self,
path.span,
ResolutionError::UnresolvedAssociatedConst(&path.segments
.last()
.unwrap()
.identifier
.name
.as_str()));
2015-12-11 20:59:11 +13:00
self.record_def(pattern.id, err_path_resolution());
}
intravisit::walk_pat(self, pattern);
}
2016-02-14 15:25:12 +03:00
PatKind::Struct(ref path, _, _) => {
2016-03-08 23:28:10 +00:00
match self.resolve_path(pat_id, path, 0, TypeNS) {
2016-04-07 00:42:29 +00:00
Ok(definition) => {
self.record_def(pattern.id, definition);
}
2016-04-07 00:42:29 +00:00
Err(true) => self.record_def(pattern.id, err_path_resolution()),
Err(false) => {
resolve_error(
self,
path.span,
2015-07-14 19:42:38 +02:00
ResolutionError::DoesNotNameAStruct(
2016-02-09 21:27:42 +01:00
&path_names_to_string(path, 0))
);
2015-12-11 20:59:11 +13:00
self.record_def(pattern.id, err_path_resolution());
}
}
intravisit::walk_path(self, path);
}
2016-02-14 15:25:12 +03:00
PatKind::Lit(_) | PatKind::Range(..) => {
intravisit::walk_pat(self, pattern);
}
_ => {
// Nothing to do.
}
}
true
});
}
fn resolve_bare_identifier_pattern(&mut self, ident: hir::Ident, span: Span)
2014-04-14 11:30:59 +03:00
-> BareIdentifierPatternResolution {
let binding = match self.resolve_ident_in_lexical_scope(ident, ValueNS, true) {
Some(LexicalScopeBinding::Item(binding)) => binding,
_ => return BareIdentifierPatternUnresolved,
};
let def = binding.def().unwrap();
match def {
Def::Variant(..) | Def::Struct(..) => FoundStructOrEnumVariant(def),
Def::Const(..) | Def::AssociatedConst(..) => FoundConst(def, ident.unhygienic_name),
Def::Static(..) => {
let error = ResolutionError::StaticVariableReference(binding);
resolve_error(self, span, error);
BareIdentifierPatternUnresolved
}
_ => BareIdentifierPatternUnresolved,
}
}
/// Handles paths that may refer to associated items
fn resolve_possibly_assoc_item(&mut self,
id: NodeId,
2015-07-31 00:04:06 -07:00
maybe_qself: Option<&hir::QSelf>,
path: &Path,
2016-03-08 23:28:10 +00:00
namespace: Namespace)
2015-10-26 20:31:11 +01:00
-> AssocItemResolveResult {
let max_assoc_types;
match maybe_qself {
Some(qself) => {
if qself.position == 0 {
return TypecheckRequired;
}
max_assoc_types = path.segments.len() - qself.position;
// Make sure the trait is valid.
let _ = self.resolve_trait_reference(id, path, max_assoc_types);
}
None => {
max_assoc_types = path.segments.len();
}
}
let mut resolution = self.with_no_errors(|this| {
2016-04-07 00:42:29 +00:00
this.resolve_path(id, path, 0, namespace).ok()
});
for depth in 1..max_assoc_types {
if resolution.is_some() {
break;
}
self.with_no_errors(|this| {
2016-04-07 00:42:29 +00:00
resolution = this.resolve_path(id, path, depth, TypeNS).ok();
});
}
if let Some(Def::Mod(_)) = resolution.map(|r| r.base_def) {
// A module is not a valid type or value.
resolution = None;
}
ResolveAttempt(resolution)
}
/// Skips `path_depth` trailing segments, which is also reflected in the
/// returned value. See `hir::def::PathResolution` for more info.
2016-03-17 01:05:29 +00:00
fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, namespace: Namespace)
2016-04-07 00:42:29 +00:00
-> Result<PathResolution, bool /* true if an error was reported */ > {
let span = path.span;
2015-10-26 20:31:11 +01:00
let segments = &path.segments[..path.segments.len() - path_depth];
2016-02-25 03:36:17 +00:00
let mk_res = |def| PathResolution::new(def, path_depth);
if path.global {
let binding = self.resolve_crate_relative_path(span, segments, namespace);
return binding.map(|binding| mk_res(binding.def().unwrap()));
}
// Try to find a path to an item in a module.
let last_ident = segments.last().unwrap().identifier;
// Resolve a single identifier with fallback to primitive types
let resolve_identifier_with_fallback = |this: &mut Self, record_used| {
let def = this.resolve_identifier(last_ident, namespace, record_used);
match def {
None | Some(LocalDef{def: Def::Mod(..), ..}) if namespace == TypeNS =>
this.primitive_type_table
.primitive_types
.get(&last_ident.unhygienic_name)
.map_or(def, |prim_ty| Some(LocalDef::from_def(Def::PrimTy(*prim_ty)))),
_ => def
}
};
if segments.len() == 1 {
// In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
// don't report an error right away, but try to fallback to a primitive type.
// So, we are still able to successfully resolve something like
//
// use std::u8; // bring module u8 in scope
// fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
// u8::max_value() // OK, resolves to associated function <u8>::max_value,
// // not to non-existent std::u8::max_value
// }
//
// Such behavior is required for backward compatibility.
// The same fallback is used when `a` resolves to nothing.
2016-04-07 00:42:29 +00:00
let def = resolve_identifier_with_fallback(self, true).ok_or(false);
return def.and_then(|def| self.adjust_local_def(def, span).ok_or(true)).map(mk_res);
2015-03-30 12:21:20 +13:00
}
let unqualified_def = resolve_identifier_with_fallback(self, false);
let qualified_binding = self.resolve_module_relative_path(span, segments, namespace);
match (qualified_binding, unqualified_def) {
(Ok(binding), Some(ref ud)) if binding.def().unwrap() == ud.def => {
2015-03-30 12:21:20 +13:00
self.session
.add_lint(lint::builtin::UNUSED_QUALIFICATIONS,
2015-10-26 20:31:11 +01:00
id,
span,
2015-03-30 12:21:20 +13:00
"unnecessary qualification".to_string());
}
_ => {}
}
2015-03-30 12:21:20 +13:00
qualified_binding.map(|binding| mk_res(binding.def().unwrap()))
}
// Resolve a single identifier
2013-10-02 14:33:01 +02:00
fn resolve_identifier(&mut self,
identifier: hir::Ident,
namespace: Namespace,
record_used: bool)
-> Option<LocalDef> {
if identifier.unhygienic_name == keywords::Invalid.name() {
return Some(LocalDef::from_def(Def::Err));
}
self.resolve_ident_in_lexical_scope(identifier, namespace, record_used)
.map(LexicalScopeBinding::local_def)
}
// Resolve a local definition, potentially adjusting for closures.
fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Option<Def> {
let ribs = match local_def.ribs {
2015-10-26 20:31:11 +01:00
Some((TypeNS, i)) => &self.type_ribs[i + 1..],
Some((ValueNS, i)) => &self.value_ribs[i + 1..],
_ => &[] as &[_],
};
let mut def = local_def.def;
match def {
Def::Upvar(..) => {
span_bug!(span, "unexpected {:?} in bindings", def)
}
Def::Local(_, node_id) => {
for rib in ribs {
match rib.kind {
NormalRibKind | ModuleRibKind(..) => {
// Nothing to do. Continue.
}
ClosureRibKind(function_id) => {
let prev_def = def;
let node_def_id = self.ast_map.local_def_id(node_id);
2015-10-26 20:31:11 +01:00
let seen = self.freevars_seen
.entry(function_id)
.or_insert_with(|| NodeMap());
if let Some(&index) = seen.get(&node_id) {
def = Def::Upvar(node_def_id, node_id, index, function_id);
continue;
}
2015-10-26 20:31:11 +01:00
let vec = self.freevars
.entry(function_id)
.or_insert_with(|| vec![]);
let depth = vec.len();
2015-10-26 20:31:11 +01:00
vec.push(Freevar {
def: prev_def,
span: span,
});
def = Def::Upvar(node_def_id, node_id, depth, function_id);
seen.insert(node_id, depth);
}
ItemRibKind | MethodRibKind => {
// This was an attempt to access an upvar inside a
// named function item. This is not allowed, so we
// report an error.
2015-10-26 20:31:11 +01:00
resolve_error(self,
span,
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem);
return None;
}
ConstantItemRibKind => {
// Still doesn't deal with upvars
2015-10-26 20:31:11 +01:00
resolve_error(self,
span,
ResolutionError::AttemptToUseNonConstantValueInConstant);
return None;
}
}
}
}
Def::TyParam(..) | Def::SelfTy(..) => {
for rib in ribs {
match rib.kind {
NormalRibKind | MethodRibKind | ClosureRibKind(..) |
ModuleRibKind(..) => {
// Nothing to do. Continue.
}
ItemRibKind => {
// This was an attempt to use a type parameter outside
// its scope.
resolve_error(self,
span,
ResolutionError::TypeParametersFromOuterFunction);
return None;
}
ConstantItemRibKind => {
// see #9186
resolve_error(self, span, ResolutionError::OuterTypeParameterContext);
return None;
}
}
}
}
_ => {}
}
return Some(def);
}
// resolve a "module-relative" path, e.g. a::b::c
2013-10-02 14:33:01 +02:00
fn resolve_module_relative_path(&mut self,
span: Span,
2015-07-31 00:04:06 -07:00
segments: &[hir::PathSegment],
namespace: Namespace)
-> Result<&'a NameBinding<'a>,
bool /* true if an error was reported */> {
2015-10-26 20:31:11 +01:00
let module_path = segments.split_last()
.unwrap()
.1
.iter()
.map(|ps| ps.identifier.name)
.collect::<Vec<_>>();
2013-04-12 01:15:30 -04:00
let containing_module;
2016-03-08 21:44:19 +00:00
match self.resolve_module_path(&module_path, UseLexicalScope, span) {
Failed(err) => {
let (span, msg) = match err {
Some((span, msg)) => (span, msg),
None => {
let msg = format!("Use of undeclared type or module `{}`",
names_to_string(&module_path));
(span, msg)
}
};
2016-02-09 21:27:42 +01:00
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
2016-04-07 00:42:29 +00:00
return Err(true);
}
2016-04-07 00:42:29 +00:00
Indeterminate => return Err(false),
2016-02-25 03:36:17 +00:00
Success(resulting_module) => {
containing_module = resulting_module;
}
}
let name = segments.last().unwrap().identifier.name;
2016-01-31 04:25:49 +00:00
let result = self.resolve_name_in_module(containing_module, name, namespace, false, true);
result.success().map(|binding| {
self.check_privacy(name, binding, span);
binding
2016-04-07 00:42:29 +00:00
}).ok_or(false)
}
/// Invariant: This must be called only during main resolution, not during
/// import resolution.
2013-10-02 14:33:01 +02:00
fn resolve_crate_relative_path(&mut self,
span: Span,
2015-07-31 00:04:06 -07:00
segments: &[hir::PathSegment],
Extract privacy checking from name resolution This commit is the culmination of my recent effort to refine Rust's notion of privacy and visibility among crates. The major goals of this commit were to remove privacy checking from resolve for the sake of sane error messages, and to attempt a much more rigid and well-tested implementation of visibility throughout rust. The implemented rules for name visibility are: 1. Everything pub from the root namespace is visible to anyone 2. You may access any private item of your ancestors. "Accessing a private item" depends on what the item is, so for a function this means that you can call it, but for a module it means that you can look inside of it. Once you look inside a private module, any accessed item must be "pub from the root" where the new root is the private module that you looked into. These rules required some more analysis results to get propagated from trans to privacy in the form of a few hash tables. I added a new test in which my goal was to showcase all of the privacy nuances of the language, and I hope to place any new bugs into this file to prevent regressions. Overall, I was unable to completely remove the notion of privacy from resolve. One use of privacy is for dealing with glob imports. Essentially a glob import can only import *public* items from the destination, and because this must be done at namespace resolution time, resolve must maintain the notion of "what items are public in a module". There are some sad approximations of privacy, but I unfortunately can't see clear methods to extract them outside. The other use case of privacy in resolve now is one that must stick around regardless of glob imports. When dealing with privacy, checking a private path needs to know "what the last private thing was" when looking at a path. Resolve is the only compiler pass which knows the answer to this question, so it maintains the answer on a per-path resolution basis (works similarly to the def_map generated). Closes #8215
2013-10-05 14:37:39 -07:00
namespace: Namespace)
-> Result<&'a NameBinding<'a>,
bool /* true if an error was reported */> {
2015-10-26 20:31:11 +01:00
let module_path = segments.split_last()
.unwrap()
.1
.iter()
.map(|ps| ps.identifier.name)
.collect::<Vec<_>>();
let root_module = self.graph_root;
2013-04-12 01:15:30 -04:00
let containing_module;
2012-08-06 12:34:08 -07:00
match self.resolve_module_path_from_root(root_module,
2016-01-29 23:34:58 +00:00
&module_path,
0,
2016-02-25 03:36:17 +00:00
span) {
Failed(err) => {
let (span, msg) = match err {
Some((span, msg)) => (span, msg),
None => {
let msg = format!("Use of undeclared module `::{}`",
2016-01-29 23:34:58 +00:00
names_to_string(&module_path));
(span, msg)
}
};
2016-02-09 21:27:42 +01:00
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
2016-04-07 00:42:29 +00:00
return Err(true);
}
2016-04-07 00:42:29 +00:00
Indeterminate => return Err(false),
2016-02-25 03:36:17 +00:00
Success(resulting_module) => {
containing_module = resulting_module;
}
}
let name = segments.last().unwrap().identifier.name;
2016-02-25 03:36:17 +00:00
let result = self.resolve_name_in_module(containing_module, name, namespace, false, true);
result.success().map(|binding| {
self.check_privacy(name, binding, span);
binding
2016-04-07 00:42:29 +00:00
}).ok_or(false)
}
2015-10-26 20:31:11 +01:00
fn with_no_errors<T, F>(&mut self, f: F) -> T
where F: FnOnce(&mut Resolver) -> T
2014-12-08 20:26:43 -05:00
{
self.emit_errors = false;
let rs = f(self);
self.emit_errors = true;
rs
}
fn find_fallback_in_self_type(&mut self, name: Name) -> FallbackSuggestion {
fn extract_node_id(t: &Ty) -> Option<NodeId> {
match t.node {
TyPath(None, _) => Some(t.id),
TyRptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
// This doesn't handle the remaining `Ty` variants as they are not
// that commonly the self_type, it might be interesting to provide
// support for those in future.
_ => None,
}
}
if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
// Look for a field with the same name in the current self_type.
match self.def_map.get(&node_id).map(|d| d.full_def()) {
Some(Def::Enum(did)) |
Some(Def::TyAlias(did)) |
Some(Def::Struct(did)) |
Some(Def::Variant(_, did)) => match self.structs.get(&did) {
None => {}
Some(fields) => {
if fields.iter().any(|&field_name| name == field_name) {
return Field;
}
}
},
_ => {} // Self type didn't resolve properly
}
}
// Look for a method in the current trait.
if let Some((trait_did, ref trait_ref)) = self.current_trait_ref {
2016-04-26 08:29:13 +00:00
if let Some(&is_static_method) = self.trait_item_map.get(&(name, trait_did)) {
if is_static_method {
return TraitMethod(path_names_to_string(&trait_ref.path, 0));
} else {
return TraitItem;
}
}
}
NoSuggestion
}
fn find_best_match(&mut self, name: &str) -> SuggestionType {
if let Some(macro_name) = self.session.available_macros
.borrow().iter().find(|n| n.as_str() == name) {
return SuggestionType::Macro(format!("{}!", macro_name));
}
let names = self.value_ribs
.iter()
.rev()
.flat_map(|rib| rib.bindings.keys());
if let Some(found) = find_best_match_for_name(names, name, None) {
2016-02-09 21:27:42 +01:00
if name != found {
return SuggestionType::Function(found);
}
} SuggestionType::NotFound
}
fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
2012-08-17 16:53:07 -07:00
// First, record candidate traits for this expression if it could
// result in the invocation of a method call.
self.record_candidate_traits_for_expr_if_necessary(expr);
// Next, resolve the node.
2012-08-06 12:34:08 -07:00
match expr.node {
ExprPath(ref maybe_qself, ref path) => {
2015-10-26 20:31:11 +01:00
let resolution = match self.resolve_possibly_assoc_item(expr.id,
maybe_qself.as_ref(),
path,
2016-03-08 23:28:10 +00:00
ValueNS) {
2015-10-26 20:31:11 +01:00
// `<T>::a::b::c` is resolved by typeck alone.
TypecheckRequired => {
let method_name = path.segments.last().unwrap().identifier.name;
let traits = self.get_traits_containing_item(method_name);
self.trait_map.insert(expr.id, traits);
intravisit::walk_expr(self, expr);
2015-10-26 20:31:11 +01:00
return;
}
ResolveAttempt(resolution) => resolution,
};
2015-01-30 10:09:44 +02:00
// This is a local path in the value namespace. Walk through
// scopes looking for it.
if let Some(path_res) = resolution {
// Check if struct variant
let is_struct_variant = if let Def::Variant(_, variant_id) = path_res.base_def {
self.structs.contains_key(&variant_id)
} else {
false
};
if is_struct_variant {
let _ = self.structs.contains_key(&path_res.base_def.def_id());
let path_name = path_names_to_string(path, 0);
2015-12-21 10:00:43 +13:00
let mut err = resolve_struct_error(self,
expr.span,
2016-02-09 21:27:42 +01:00
ResolutionError::StructVariantUsedAsFunction(&path_name));
2015-10-26 20:31:11 +01:00
let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
path_name);
if self.emit_errors {
err.help(&msg);
} else {
2015-12-23 19:27:20 +13:00
err.span_help(expr.span, &msg);
}
2015-12-23 19:27:20 +13:00
err.emit();
2015-12-11 20:59:11 +13:00
self.record_def(expr.id, err_path_resolution());
} else {
// Write the result into the def map.
debug!("(resolving expr) resolved `{}`",
path_names_to_string(path, 0));
// Partial resolutions will need the set of traits in scope,
// so they can be completed during typeck.
if path_res.depth != 0 {
let method_name = path.segments.last().unwrap().identifier.name;
let traits = self.get_traits_containing_item(method_name);
self.trait_map.insert(expr.id, traits);
}
self.record_def(expr.id, path_res);
}
} else {
// 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
// structs, which wouldn't result in this error.)
let path_name = path_names_to_string(path, 0);
let type_res = self.with_no_errors(|this| {
2016-03-08 23:28:10 +00:00
this.resolve_path(expr.id, path, 0, TypeNS)
});
2015-12-11 20:59:11 +13:00
self.record_def(expr.id, err_path_resolution());
2016-04-07 00:42:29 +00:00
if let Ok(Def::Struct(..)) = type_res.map(|r| r.base_def) {
2016-04-07 04:13:34 +00:00
let error_variant =
ResolutionError::StructVariantUsedAsFunction(&path_name);
2016-04-07 00:42:29 +00:00
let mut err = resolve_struct_error(self, expr.span, error_variant);
let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
path_name);
if self.emit_errors {
err.help(&msg);
2016-04-07 00:42:29 +00:00
} else {
err.span_help(expr.span, &msg);
}
err.emit();
} else {
// Keep reporting some errors even if they're ignored above.
if let Err(true) = self.resolve_path(expr.id, path, 0, ValueNS) {
// `resolve_path` already reported the error
} else {
let mut method_scope = false;
self.value_ribs.iter().rev().all(|rib| {
method_scope = match rib.kind {
MethodRibKind => true,
ItemRibKind | ConstantItemRibKind => false,
_ => return true, // Keep advancing
};
false // Stop advancing
});
if method_scope &&
&path_name[..] == keywords::SelfValue.name().as_str() {
2015-10-26 20:31:11 +01:00
resolve_error(self,
expr.span,
ResolutionError::SelfNotAvailableInStaticMethod);
} else {
let last_name = path.segments.last().unwrap().identifier.name;
let mut msg = match self.find_fallback_in_self_type(last_name) {
NoSuggestion => {
// limit search to 5 to reduce the number
// of stupid suggestions
match self.find_best_match(&path_name) {
SuggestionType::Macro(s) => {
format!("the macro `{}`", s)
}
SuggestionType::Function(s) => format!("`{}`", s),
SuggestionType::NotFound => "".to_string(),
}
}
Field => format!("`self.{}`", path_name),
2015-10-26 20:31:11 +01:00
TraitItem => format!("to call `self.{}`", path_name),
TraitMethod(path_str) =>
2015-10-26 20:31:11 +01:00
format!("to call `{}::{}`", path_str, path_name),
};
let mut context = UnresolvedNameContext::Other;
if !msg.is_empty() {
msg = format!(". Did you mean {}?", msg);
} else {
// we check if this a module and if so, we display a help
// message
let name_path = path.segments.iter()
.map(|seg| seg.identifier.name)
.collect::<Vec<_>>();
2016-03-08 21:44:19 +00:00
match self.resolve_module_path(&name_path[..],
2016-01-26 09:52:33 +00:00
UseLexicalScope,
expr.span) {
Success(_) => {
context = UnresolvedNameContext::PathIsMod(parent);
},
_ => {},
};
}
resolve_error(self,
expr.span,
ResolutionError::UnresolvedName(
2016-02-09 21:27:42 +01:00
&path_name, &msg, context));
}
2012-08-22 20:40:42 +02:00
}
}
}
intravisit::walk_expr(self, expr);
}
ExprStruct(ref path, _, _) => {
// Resolve the path to the structure it goes to. We don't
// check to ensure that the path is actually a structure; that
// is checked later during typeck.
2016-03-08 23:28:10 +00:00
match self.resolve_path(expr.id, path, 0, TypeNS) {
2016-04-07 00:42:29 +00:00
Ok(definition) => self.record_def(expr.id, definition),
Err(true) => self.record_def(expr.id, err_path_resolution()),
Err(false) => {
debug!("(resolving expression) didn't find struct def",);
resolve_error(self,
path.span,
2015-07-14 19:42:38 +02:00
ResolutionError::DoesNotNameAStruct(
2016-02-09 21:27:42 +01:00
&path_names_to_string(path, 0))
);
2015-12-11 20:59:11 +13:00
self.record_def(expr.id, err_path_resolution());
}
}
intravisit::walk_expr(self, expr);
}
2014-07-25 20:12:51 -04:00
ExprLoop(_, Some(label)) | ExprWhile(_, _, Some(label)) => {
self.with_label_rib(|this| {
let def = Def::Label(expr.id);
2014-03-20 19:49:20 -07:00
2013-12-21 13:58:11 -08:00
{
let rib = this.label_ribs.last_mut().unwrap();
rib.bindings.insert(label.name, def);
2013-12-21 13:58:11 -08:00
}
intravisit::walk_expr(this, expr);
})
}
ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
match self.search_label(label.node.name) {
None => {
2015-12-11 20:59:11 +13:00
self.record_def(expr.id, err_path_resolution());
resolve_error(self,
label.span,
ResolutionError::UndeclaredLabel(&label.node.name.as_str()))
}
Some(def @ Def::Label(_)) => {
// Since this def is a label, it is never read.
2015-10-26 20:31:11 +01:00
self.record_def(expr.id,
PathResolution {
base_def: def,
depth: 0,
})
}
Some(_) => {
span_bug!(expr.span, "label wasn't mapped to a label def!")
}
}
}
ExprField(ref subexpression, _) => {
self.resolve_expr(subexpression, Some(expr));
}
ExprMethodCall(_, ref types, ref arguments) => {
let mut arguments = arguments.iter();
self.resolve_expr(arguments.next().unwrap(), Some(expr));
for argument in arguments {
self.resolve_expr(argument, None);
}
for ty in types.iter() {
self.visit_ty(ty);
}
}
2012-08-03 19:59:04 -07:00
_ => {
intravisit::walk_expr(self, expr);
}
}
}
2014-01-06 14:00:46 +02:00
fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
2012-08-06 12:34:08 -07:00
match expr.node {
ExprField(_, name) => {
// FIXME(#6890): Even though you can't treat a method like a
// field, we need to add any trait methods we find that match
// the field name so that we can do some nice error reporting
// later on in typeck.
let traits = self.get_traits_containing_item(name.node);
self.trait_map.insert(expr.id, traits);
}
ExprMethodCall(name, _, _) => {
2015-10-26 20:31:11 +01:00
debug!("(recording candidate traits for expr) recording traits for {}",
expr.id);
let traits = self.get_traits_containing_item(name.node);
self.trait_map.insert(expr.id, traits);
}
_ => {
// Nothing to do.
}
}
}
2016-04-19 22:43:10 +09:00
fn get_traits_containing_item(&mut self, name: Name) -> Vec<TraitCandidate> {
2015-10-26 20:31:11 +01:00
debug!("(getting traits containing item) looking for '{}'", name);
2014-04-22 19:06:43 +03:00
2016-04-19 22:43:10 +09:00
fn add_trait_info(found_traits: &mut Vec<TraitCandidate>,
trait_def_id: DefId,
import_id: Option<NodeId>,
name: Name) {
debug!("(adding trait info) found trait {:?} for method '{}'",
2015-10-26 20:31:11 +01:00
trait_def_id,
name);
2016-04-19 22:43:10 +09:00
found_traits.push(TraitCandidate {
def_id: trait_def_id,
import_id: import_id,
});
2014-04-22 19:06:43 +03:00
}
let mut found_traits = Vec::new();
2016-03-07 23:10:53 +00:00
// Look for the current trait.
if let Some((trait_def_id, _)) = self.current_trait_ref {
if self.trait_item_map.contains_key(&(name, trait_def_id)) {
2016-04-19 22:43:10 +09:00
add_trait_info(&mut found_traits, trait_def_id, None, name);
2014-04-22 19:06:43 +03:00
}
2016-03-07 23:10:53 +00:00
}
2016-03-07 23:10:53 +00:00
let mut search_module = self.current_module;
loop {
2014-04-22 19:06:43 +03:00
// Look for trait children.
2016-04-18 00:00:18 +00:00
let mut search_in_module = |module: Module<'a>| {
let mut traits = module.traits.borrow_mut();
if traits.is_none() {
let mut collected_traits = Vec::new();
2016-04-25 05:34:59 +00:00
module.for_each_child(|name, ns, binding| {
2016-04-18 00:00:18 +00:00
if ns != TypeNS { return }
if let Some(Def::Trait(_)) = binding.def() {
2016-04-25 05:34:59 +00:00
collected_traits.push((name, binding));
2016-04-18 00:00:18 +00:00
}
});
*traits = Some(collected_traits.into_boxed_slice());
}
2016-04-18 00:00:18 +00:00
2016-04-25 05:34:59 +00:00
for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
2016-04-18 00:00:18 +00:00
let trait_def_id = binding.def().unwrap().def_id();
if self.trait_item_map.contains_key(&(name, trait_def_id)) {
2016-04-19 22:43:10 +09:00
let mut import_id = None;
if let NameBindingKind::Import { directive, .. } = binding.kind {
let id = directive.id;
self.maybe_unused_trait_imports.insert(id);
import_id = Some(id);
}
add_trait_info(&mut found_traits, trait_def_id, import_id, name);
self.record_use(trait_name, binding);
2016-04-18 00:00:18 +00:00
}
}
};
2016-03-09 01:46:46 +00:00
search_in_module(search_module);
match search_module.parent_link {
2016-03-09 01:46:46 +00:00
NoParentLink | ModuleParentLink(..) => {
search_module.prelude.borrow().map(search_in_module);
break;
}
2014-04-22 19:06:43 +03:00
BlockParentLink(parent_module, _) => {
search_module = parent_module;
}
2014-04-22 19:06:43 +03:00
}
}
2014-04-22 19:06:43 +03:00
found_traits
}
/// When name resolution fails, this method can be used to look up candidate
/// entities with the expected name. It allows filtering them using the
/// supplied predicate (which should be used to only accept the types of
/// definitions expected e.g. traits). The lookup spans across all crates.
///
/// NOTE: The method does not look into imports, but this is not a problem,
/// since we report the definitions (thus, the de-aliased imports).
fn lookup_candidates<FilterFn>(&mut self,
lookup_name: Name,
namespace: Namespace,
filter_fn: FilterFn) -> SuggestedCandidates
where FilterFn: Fn(Def) -> bool {
let mut lookup_results = Vec::new();
let mut worklist = Vec::new();
worklist.push((self.graph_root, Vec::new(), false));
while let Some((in_module,
path_segments,
in_module_is_extern)) = worklist.pop() {
self.populate_module_if_necessary(in_module);
in_module.for_each_child(|name, ns, name_binding| {
// avoid imports entirely
if name_binding.is_import() { return; }
// collect results based on the filter function
if let Some(def) = name_binding.def() {
if name == lookup_name && ns == namespace && filter_fn(def) {
// create the path
let ident = hir::Ident::from_name(name);
let params = PathParameters::none();
let segment = PathSegment {
identifier: ident,
parameters: params,
};
let span = name_binding.span;
let mut segms = path_segments.clone();
segms.push(segment);
let segms = HirVec::from_vec(segms);
let path = Path {
span: span,
global: true,
segments: segms,
};
// the entity is accessible in the following cases:
// 1. if it's defined in the same crate, it's always
// accessible (since private entities can be made public)
// 2. if it's defined in another crate, it's accessible
// only if both the module is public and the entity is
// declared as public (due to pruning, we don't explore
// outside crate private modules => no need to check this)
if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
lookup_results.push(path);
}
}
}
// collect submodules to explore
if let Some(module) = name_binding.module() {
// form the path
let path_segments = match module.parent_link {
NoParentLink => path_segments.clone(),
ModuleParentLink(_, name) => {
let mut paths = path_segments.clone();
let ident = hir::Ident::from_name(name);
let params = PathParameters::none();
let segm = PathSegment {
identifier: ident,
parameters: params,
};
paths.push(segm);
paths
}
_ => bug!(),
};
if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
// add the module to the lookup
let is_extern = in_module_is_extern || name_binding.is_extern_crate();
worklist.push((module, path_segments, is_extern));
}
}
})
}
SuggestedCandidates {
name: lookup_name.as_str().to_string(),
candidates: lookup_results,
}
}
fn record_def(&mut self, node_id: NodeId, resolution: PathResolution) {
debug!("(recording def) recording {:?} for {}", resolution, node_id);
if let Some(prev_res) = self.def_map.insert(node_id, resolution) {
let span = self.ast_map.opt_span(node_id).unwrap_or(codemap::DUMMY_SP);
span_bug!(span,
"path resolved multiple times ({:?} before, {:?} now)",
prev_res,
resolution);
2014-09-18 17:05:52 -04:00
}
}
2013-10-02 14:33:01 +02:00
fn enforce_default_binding_mode(&mut self,
2015-10-26 20:31:11 +01:00
pat: &Pat,
pat_binding_mode: BindingMode,
descr: &str) {
match pat_binding_mode {
BindByValue(_) => {}
2013-11-28 12:22:53 -08:00
BindByRef(..) => {
resolve_error(self,
pat.span,
2015-07-14 19:42:38 +02:00
ResolutionError::CannotUseRefBindingModeWith(descr));
}
}
}
fn resolve_visibility(&mut self, vis: &hir::Visibility) -> ty::Visibility {
let (path, id) = match *vis {
hir::Public => return ty::Visibility::Public,
hir::Visibility::Crate => return ty::Visibility::Restricted(ast::CRATE_NODE_ID),
hir::Visibility::Restricted { ref path, id } => (path, id),
hir::Inherited => {
let current_module =
self.get_nearest_normal_module_parent_or_self(self.current_module);
let id = self.ast_map.as_local_node_id(current_module.def_id().unwrap()).unwrap();
return ty::Visibility::Restricted(id);
}
};
let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier.name).collect();
let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, path.span) {
Success(module) => {
let def = module.def.unwrap();
let path_resolution = PathResolution { base_def: def, depth: 0 };
self.def_map.insert(id, path_resolution);
ty::Visibility::Restricted(self.ast_map.as_local_node_id(def.def_id()).unwrap())
}
Failed(Some((span, msg))) => {
self.session.span_err(span, &format!("failed to resolve module path. {}", msg));
ty::Visibility::Public
}
_ => {
self.session.span_err(path.span, "unresolved module path");
ty::Visibility::Public
}
};
if !self.is_accessible(vis) {
let msg = format!("visibilities can only be restricted to ancestor modules");
self.session.span_err(path.span, &msg);
}
vis
}
fn is_accessible(&self, vis: ty::Visibility) -> bool {
let current_module = self.get_nearest_normal_module_parent_or_self(self.current_module);
let node_id = self.ast_map.as_local_node_id(current_module.def_id().unwrap()).unwrap();
vis.is_accessible_from(node_id, self)
}
fn check_privacy(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Span) {
if !self.is_accessible(binding.vis) {
self.privacy_errors.push(PrivacyError(span, name, binding));
}
}
fn report_privacy_errors(&self) {
if self.privacy_errors.len() == 0 { return }
let mut reported_spans = HashSet::new();
for &PrivacyError(span, name, binding) in &self.privacy_errors {
if !reported_spans.insert(span) { continue }
if binding.is_extern_crate() {
// Warn when using an inaccessible extern crate.
let node_id = binding.module().unwrap().extern_crate_id.unwrap();
let msg = format!("extern crate `{}` is private", name);
self.session.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, node_id, span, msg);
} else {
let def = binding.def().unwrap();
self.session.span_err(span, &format!("{} `{}` is private", def.kind_name(), name));
}
}
}
fn report_conflict(&self,
parent: Module,
name: Name,
ns: Namespace,
binding: &NameBinding,
old_binding: &NameBinding) {
// Error on the second of two conflicting names
if old_binding.span.lo > binding.span.lo {
return self.report_conflict(parent, name, ns, old_binding, binding);
}
let container = match parent.def {
Some(Def::Mod(_)) => "module",
Some(Def::Trait(_)) => "trait",
None => "block",
_ => "enum",
};
let (participle, noun) = match old_binding.is_import() || old_binding.is_extern_crate() {
true => ("imported", "import"),
false => ("defined", "definition"),
};
let span = binding.span;
let msg = {
let kind = match (ns, old_binding.module()) {
(ValueNS, _) => "a value",
(TypeNS, Some(module)) if module.extern_crate_id.is_some() => "an extern crate",
(TypeNS, Some(module)) if module.is_normal() => "a module",
(TypeNS, Some(module)) if module.is_trait() => "a trait",
(TypeNS, _) => "a type",
};
format!("{} named `{}` has already been {} in this {}",
kind, name, participle, container)
};
let mut err = match (old_binding.is_extern_crate(), binding.is_extern_crate()) {
(true, true) => struct_span_err!(self.session, span, E0259, "{}", msg),
(true, _) | (_, true) if binding.is_import() || old_binding.is_import() =>
struct_span_err!(self.session, span, E0254, "{}", msg),
(true, _) | (_, true) => struct_span_err!(self.session, span, E0260, "{}", msg),
_ => match (old_binding.is_import(), binding.is_import()) {
(false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
(true, true) => struct_span_err!(self.session, span, E0252, "{}", msg),
_ => struct_span_err!(self.session, span, E0255, "{}", msg),
},
};
if old_binding.span != codemap::DUMMY_SP {
err.span_note(old_binding.span, &format!("previous {} of `{}` here", noun, name));
}
err.emit();
}
}
fn names_to_string(names: &[Name]) -> String {
let mut first = true;
let mut result = String::new();
for name in names {
if first {
first = false
} else {
result.push_str("::")
}
result.push_str(&name.as_str());
2015-10-26 20:31:11 +01:00
}
result
}
fn path_names_to_string(path: &Path, depth: usize) -> String {
2015-10-26 20:31:11 +01:00
let names: Vec<ast::Name> = path.segments[..path.segments.len() - depth]
.iter()
.map(|seg| seg.identifier.name)
.collect();
names_to_string(&names[..])
}
/// When an entity with a given name is not available in scope, we search for
/// entities with that name in all crates. This method allows outputting the
/// results of this search in a programmer-friendly way
fn show_candidates(session: &mut DiagnosticBuilder,
candidates: &SuggestedCandidates) {
let paths = &candidates.candidates;
if paths.len() > 0 {
// don't show more than MAX_CANDIDATES results, so
// we're consistent with the trait suggestions
const MAX_CANDIDATES: usize = 5;
// we want consistent results across executions, but candidates are produced
// by iterating through a hash map, so make sure they are ordered:
let mut path_strings: Vec<_> = paths.into_iter()
.map(|p| path_names_to_string(&p, 0))
.collect();
path_strings.sort();
// behave differently based on how many candidates we have:
if !paths.is_empty() {
if paths.len() == 1 {
session.help(
&format!("you can import it into scope: `use {};`.",
&path_strings[0]),
);
} else {
session.help("you can import several candidates \
into scope (`use ...;`):");
let count = path_strings.len() as isize - MAX_CANDIDATES as isize + 1;
for (idx, path_string) in path_strings.iter().enumerate() {
if idx == MAX_CANDIDATES - 1 && count > 1 {
session.help(
&format!(" and {} other candidates", count).to_string(),
);
break;
} else {
session.help(
&format!(" `{}`", path_string).to_string(),
);
}
}
}
}
} else {
// nothing found:
session.help(
&format!("no candidates by the name of `{}` found in your \
project; maybe you misspelled the name or forgot to import \
an external crate?", candidates.name.to_string()),
);
};
}
/// A somewhat inefficient routine to obtain the name of a module.
fn module_to_string(module: Module) -> String {
let mut names = Vec::new();
fn collect_mod(names: &mut Vec<ast::Name>, module: Module) {
match module.parent_link {
NoParentLink => {}
ModuleParentLink(ref module, name) => {
names.push(name);
collect_mod(names, module);
}
BlockParentLink(ref module, _) => {
// danger, shouldn't be ident?
names.push(token::intern("<opaque>"));
collect_mod(names, module);
}
}
}
collect_mod(&mut names, module);
if names.is_empty() {
return "???".to_string();
}
names_to_string(&names.into_iter().rev().collect::<Vec<ast::Name>>())
}
2015-12-11 20:59:11 +13:00
fn err_path_resolution() -> PathResolution {
PathResolution {
base_def: Def::Err,
2015-12-11 20:59:11 +13:00
depth: 0,
}
}
pub struct CrateMap {
2015-11-04 00:02:22 -06:00
pub def_map: RefCell<DefMap>,
pub freevars: FreevarMap,
2016-04-19 22:43:10 +09:00
pub maybe_unused_trait_imports: NodeSet,
pub export_map: ExportMap,
pub trait_map: TraitMap,
2015-10-26 20:31:11 +01:00
pub glob_map: Option<GlobMap>,
}
2015-03-30 09:38:44 -04:00
#[derive(PartialEq,Copy, Clone)]
pub enum MakeGlobMap {
Yes,
2015-10-26 20:31:11 +01:00
No,
}
/// Entry point to crate resolution.
pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
2015-07-31 00:04:06 -07:00
ast_map: &'a hir_map::Map<'tcx>,
make_glob_map: MakeGlobMap)
-> CrateMap {
// Currently, we ignore the name resolution data structures for
// the purposes of dependency tracking. Instead we will run name
// resolution and include its output in the hash of each item,
// much like we do for macro expansion. In other words, the hash
// reflects not just its contents but the results of name
// resolution on those contents. Hopefully we'll push this back at
// some point.
let _task = ast_map.dep_graph.in_task(DepNode::Resolve);
let krate = ast_map.krate();
let arenas = Resolver::arenas();
2016-04-23 21:20:17 +00:00
let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, &arenas);
resolver.resolve_crate(krate);
check_unused::check_crate(&mut resolver, krate);
resolver.report_privacy_errors();
CrateMap {
def_map: RefCell::new(resolver.def_map),
freevars: resolver.freevars,
2016-04-19 22:43:10 +09:00
maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
export_map: resolver.export_map,
trait_map: resolver.trait_map,
glob_map: if resolver.make_glob_map {
2015-10-26 20:31:11 +01:00
Some(resolver.glob_map)
} else {
None
},
}
}
2016-04-23 21:20:17 +00:00
/// Builds a name resolution walker.
2016-03-17 01:05:29 +00:00
fn create_resolver<'a, 'tcx>(session: &'a Session,
ast_map: &'a hir_map::Map<'tcx>,
krate: &'a Crate,
make_glob_map: MakeGlobMap,
2016-04-23 21:20:17 +00:00
arenas: &'a ResolverArenas<'a>)
2016-03-17 01:05:29 +00:00
-> Resolver<'a, 'tcx> {
let mut resolver = Resolver::new(session, ast_map, make_glob_map, arenas);
2016-03-02 10:22:24 +00:00
resolver.build_reduced_graph(krate);
resolve_imports::resolve_imports(&mut resolver);
resolver
}
__build_diagnostic_array! { librustc_resolve, DIAGNOSTICS }