Fixes for #8625 to prevent assigning to `&mut` in borrowed or aliasable locations. The old code was insufficient in that it failed to catch bizarre cases like `& &mut &mut`.
r? @pnkfelix
ast::def_method(did0.tr(xcx), did1.map(|did1| did1.tr(xcx)))
}
ast::def_self_ty(nid) => { ast::def_self_ty(xcx.tr_id(nid)) }
- ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) }
+ ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) }
ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }
ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) }
ast::def_static(did, m) => { ast::def_static(did.tr(xcx), m) }
}
)
}
- typeck::method_trait(did, m) => {
- typeck::method_trait(did.tr(xcx), m)
+ typeck::method_object(ref mo) => {
+ typeck::method_object(
+ typeck::method_object {
+ trait_id: mo.trait_id.tr(xcx),
+ .. *mo
+ }
+ )
}
}
}
use syntax::ast;
use syntax::ast_util;
use syntax::codemap::span;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
use util::ppaux::Repr;
#[deriving(Clone)]
reported: @mut HashSet<ast::NodeId>,
}
+struct CheckLoanVisitor;
+
+impl<'self> Visitor<CheckLoanCtxt<'self>> for CheckLoanVisitor {
+ fn visit_expr<'a>(&mut self, ex:@ast::expr, e:CheckLoanCtxt<'a>) {
+ check_loans_in_expr(self, ex, e);
+ }
+ fn visit_local(&mut self, l:@ast::Local, e:CheckLoanCtxt) {
+ check_loans_in_local(self, l, e);
+ }
+ fn visit_block(&mut self, b:&ast::Block, e:CheckLoanCtxt) {
+ check_loans_in_block(self, b, e);
+ }
+ fn visit_pat(&mut self, p:@ast::pat, e:CheckLoanCtxt) {
+ check_loans_in_pat(self, p, e);
+ }
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:CheckLoanCtxt) {
+ check_loans_in_fn(self, fk, fd, b, s, n, e);
+ }
+}
+
pub fn check_loans(bccx: @BorrowckCtxt,
dfcx_loans: &LoanDataFlow,
move_data: move_data::FlowedMoveData,
reported: @mut HashSet::new(),
};
- let vt = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: check_loans_in_expr,
- visit_local: check_loans_in_local,
- visit_block: check_loans_in_block,
- visit_pat: check_loans_in_pat,
- visit_fn: check_loans_in_fn,
- .. *oldvisit::default_visitor()
- });
- (vt.visit_block)(body, (clcx, vt));
+ let mut vt = CheckLoanVisitor;
+ vt.visit_block(body, clcx);
}
enum MoveError {
mc::cat_rvalue(*) |
mc::cat_static_item |
- mc::cat_implicit_self |
mc::cat_copied_upvar(*) |
mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
mc::cat_deref(_, _, mc::gc_ptr(*)) |
mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) => {
// Statically prohibit writes to `&mut` when aliasable
- match b.freely_aliasable() {
- None => {}
- Some(cause) => {
- this.bccx.report_aliasability_violation(
- expr.span,
- MutabilityViolation,
- cause);
- }
- }
+ check_for_aliasability_violation(this, expr, b);
}
mc::cat_deref(_, deref_count, mc::gc_ptr(ast::m_mutbl)) => {
return true; // no errors reported
}
+ fn check_for_aliasability_violation(this: &CheckLoanCtxt,
+ expr: @ast::expr,
+ cmt: mc::cmt) -> bool {
+ let mut cmt = cmt;
+
+ loop {
+ match cmt.cat {
+ mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) |
+ mc::cat_downcast(b) |
+ mc::cat_stack_upvar(b) |
+ mc::cat_deref(b, _, mc::uniq_ptr) |
+ mc::cat_interior(b, _) |
+ mc::cat_discr(b, _) => {
+ // Aliasability depends on base cmt
+ cmt = b;
+ }
+
+ mc::cat_copied_upvar(_) |
+ mc::cat_rvalue(*) |
+ mc::cat_local(*) |
+ mc::cat_arg(_) |
+ mc::cat_self(*) |
+ mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
+ mc::cat_static_item(*) |
+ mc::cat_deref(_, _, mc::gc_ptr(_)) |
+ mc::cat_deref(_, _, mc::region_ptr(m_const, _)) |
+ mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) => {
+ // Aliasability is independent of base cmt
+ match cmt.freely_aliasable() {
+ None => {
+ return true;
+ }
+ Some(cause) => {
+ this.bccx.report_aliasability_violation(
+ expr.span,
+ MutabilityViolation,
+ cause);
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
fn check_for_assignment_to_restricted_or_frozen_location(
this: &CheckLoanCtxt,
expr: @ast::expr,
// path, and check that the super path was not lent out as
// mutable or immutable (a const loan is ok).
//
+ // Mutability of a path can be dependent on the super path
+ // in two ways. First, it might be inherited mutability.
+ // Second, the pointee of an `&mut` pointer can only be
+ // mutated if it is found in an unaliased location, so we
+ // have to check that the owner location is not borrowed.
+ //
// Note that we are *not* checking for any and all
// restrictions. We are only interested in the pointers
// that the user created, whereas we add restrictions for
let mut loan_path = loan_path;
loop {
match *loan_path {
- // Peel back one layer if `loan_path` has
- // inherited mutability
- LpExtend(lp_base, mc::McInherited, _) => {
+ // Peel back one layer if, for `loan_path` to be
+ // mutable, `lp_base` must be mutable. This occurs
+ // with inherited mutability and with `&mut`
+ // pointers.
+ LpExtend(lp_base, mc::McInherited, _) |
+ LpExtend(lp_base, _, LpDeref(mc::region_ptr(ast::m_mutbl, _))) => {
loan_path = lp_base;
}
}
}
-fn check_loans_in_fn<'a>(fk: &oldvisit::fn_kind,
+fn check_loans_in_fn<'a>(visitor: &mut CheckLoanVisitor,
+ fk: &visit::fn_kind,
decl: &ast::fn_decl,
body: &ast::Block,
sp: span,
id: ast::NodeId,
- (this, visitor): (CheckLoanCtxt<'a>,
- oldvisit::vt<CheckLoanCtxt<'a>>)) {
+ this: CheckLoanCtxt<'a>) {
match *fk {
- oldvisit::fk_item_fn(*) |
- oldvisit::fk_method(*) => {
+ visit::fk_item_fn(*) |
+ visit::fk_method(*) => {
// Don't process nested items.
return;
}
- oldvisit::fk_anon(*) |
- oldvisit::fk_fn_block(*) => {
+ visit::fk_anon(*) |
+ visit::fk_fn_block(*) => {
check_captured_variables(this, id, sp);
}
}
- oldvisit::visit_fn(fk, decl, body, sp, id, (this, visitor));
+ visit::walk_fn(visitor, fk, decl, body, sp, id, this);
fn check_captured_variables(this: CheckLoanCtxt,
closure_id: ast::NodeId,
}
}
-fn check_loans_in_local<'a>(local: @ast::Local,
- (this, vt): (CheckLoanCtxt<'a>,
- oldvisit::vt<CheckLoanCtxt<'a>>)) {
- oldvisit::visit_local(local, (this, vt));
+fn check_loans_in_local<'a>(vt: &mut CheckLoanVisitor,
+ local: @ast::Local,
+ this: CheckLoanCtxt<'a>) {
+ visit::walk_local(vt, local, this);
}
-fn check_loans_in_expr<'a>(expr: @ast::expr,
- (this, vt): (CheckLoanCtxt<'a>,
- oldvisit::vt<CheckLoanCtxt<'a>>)) {
- oldvisit::visit_expr(expr, (this, vt));
+fn check_loans_in_expr<'a>(vt: &mut CheckLoanVisitor,
+ expr: @ast::expr,
+ this: CheckLoanCtxt<'a>) {
+ visit::walk_expr(vt, expr, this);
debug!("check_loans_in_expr(expr=%s)",
expr.repr(this.tcx()));
}
}
-fn check_loans_in_pat<'a>(pat: @ast::pat,
- (this, vt): (CheckLoanCtxt<'a>,
- oldvisit::vt<CheckLoanCtxt<'a>>))
+fn check_loans_in_pat<'a>(vt: &mut CheckLoanVisitor,
+ pat: @ast::pat,
+ this: CheckLoanCtxt<'a>)
{
this.check_for_conflicting_loans(pat.id);
this.check_move_out_from_id(pat.id, pat.span);
- oldvisit::visit_pat(pat, (this, vt));
+ visit::walk_pat(vt, pat, this);
}
-fn check_loans_in_block<'a>(blk: &ast::Block,
- (this, vt): (CheckLoanCtxt<'a>,
- oldvisit::vt<CheckLoanCtxt<'a>>))
+fn check_loans_in_block<'a>(vt: &mut CheckLoanVisitor,
+ blk: &ast::Block,
+ this: CheckLoanCtxt<'a>)
{
- oldvisit::visit_block(blk, (this, vt));
+ visit::walk_block(vt, blk, this);
this.check_for_conflicting_loans(blk.id);
}
use std::hashmap::{HashSet, HashMap};
use syntax::ast::*;
use syntax::ast_util;
-use syntax::oldvisit;
-use syntax::oldvisit::vt;
+use syntax::visit;
+use syntax::visit::Visitor;
use syntax::codemap::span;
#[deriving(Encodable, Decodable)]
Read // Read no matter what the type.
}
+struct ComputeModesVisitor;
+
+impl visit::Visitor<VisitContext> for ComputeModesVisitor {
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&fn_decl,
+ b:&Block, s:span, n:NodeId, e:VisitContext) {
+ compute_modes_for_fn(*self, fk, fd, b, s, n, e);
+ }
+ fn visit_expr(&mut self, ex:@expr, e:VisitContext) {
+ compute_modes_for_expr(*self, ex, e);
+ }
+ fn visit_local(&mut self, l:@Local, e:VisitContext) {
+ compute_modes_for_local(*self, l, e);
+ }
+}
+
pub fn compute_moves(tcx: ty::ctxt,
method_map: method_map,
crate: &Crate) -> MoveMaps
{
- let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_fn: compute_modes_for_fn,
- visit_expr: compute_modes_for_expr,
- visit_local: compute_modes_for_local,
- .. *oldvisit::default_visitor()
- });
+ let mut visitor = ComputeModesVisitor;
let visit_cx = VisitContext {
tcx: tcx,
method_map: method_map,
moved_variables_set: @mut HashSet::new()
}
};
- oldvisit::visit_crate(crate, (visit_cx, visitor));
+ visit::walk_crate(&mut visitor, crate, visit_cx);
return visit_cx.move_maps;
}
def_binding(nid, _) |
def_arg(nid, _) |
def_local(nid, _) |
- def_self(nid, _) => Some(nid),
+ def_self(nid) => Some(nid),
_ => None
}
///////////////////////////////////////////////////////////////////////////
// Expressions
-fn compute_modes_for_local<'a>(local: @Local,
- (cx, v): (VisitContext,
- vt<VisitContext>)) {
+fn compute_modes_for_local<'a>(v: ComputeModesVisitor,
+ local: @Local,
+ cx: VisitContext) {
cx.use_pat(local.pat);
for &init in local.init.iter() {
cx.use_expr(init, Read, v);
}
}
-fn compute_modes_for_fn(fk: &oldvisit::fn_kind,
+fn compute_modes_for_fn(v: ComputeModesVisitor,
+ fk: &visit::fn_kind,
decl: &fn_decl,
body: &Block,
span: span,
id: NodeId,
- (cx, v): (VisitContext,
- vt<VisitContext>)) {
+ cx: VisitContext) {
+ let mut v = v;
for a in decl.inputs.iter() {
cx.use_pat(a.pat);
}
- oldvisit::visit_fn(fk, decl, body, span, id, (cx, v));
+ visit::walk_fn(&mut v, fk, decl, body, span, id, cx);
}
-fn compute_modes_for_expr(expr: @expr,
- (cx, v): (VisitContext,
- vt<VisitContext>))
+fn compute_modes_for_expr(v: ComputeModesVisitor,
+ expr: @expr,
+ cx: VisitContext)
{
cx.consume_expr(expr, v);
}
impl VisitContext {
- pub fn consume_exprs(&self, exprs: &[@expr], visitor: vt<VisitContext>) {
+ pub fn consume_exprs(&self, exprs: &[@expr], visitor: ComputeModesVisitor) {
for expr in exprs.iter() {
self.consume_expr(*expr, visitor);
}
}
- pub fn consume_expr(&self, expr: @expr, visitor: vt<VisitContext>) {
+ pub fn consume_expr(&self, expr: @expr, visitor: ComputeModesVisitor) {
/*!
* Indicates that the value of `expr` will be consumed,
* meaning either copied or moved depending on its type.
};
}
- pub fn consume_block(&self, blk: &Block, visitor: vt<VisitContext>) {
+ pub fn consume_block(&self, blk: &Block, visitor: ComputeModesVisitor) {
/*!
* Indicates that the value of `blk` will be consumed,
* meaning either copied or moved depending on its type.
debug!("consume_block(blk.id=%?)", blk.id);
for stmt in blk.stmts.iter() {
- (visitor.visit_stmt)(*stmt, (*self, visitor));
+ let mut v = visitor;
+ v.visit_stmt(*stmt, *self);
}
for tail_expr in blk.expr.iter() {
pub fn use_expr(&self,
expr: @expr,
expr_mode: UseMode,
- visitor: vt<VisitContext>) {
+ visitor: ComputeModesVisitor) {
/*!
* Indicates that `expr` is used with a given mode. This will
* in turn trigger calls to the subcomponents of `expr`.
expr: &expr,
receiver_expr: @expr,
arg_exprs: &[@expr],
- visitor: vt<VisitContext>)
+ visitor: ComputeModesVisitor)
-> bool {
if !self.method_map.contains_key(&expr.id) {
return false;
return true;
}
- pub fn consume_arm(&self, arm: &arm, visitor: vt<VisitContext>) {
+ pub fn consume_arm(&self, arm: &arm, visitor: ComputeModesVisitor) {
for pat in arm.pats.iter() {
self.use_pat(*pat);
}
pub fn use_receiver(&self,
receiver_expr: @expr,
- visitor: vt<VisitContext>) {
+ visitor: ComputeModesVisitor) {
self.use_fn_arg(receiver_expr, visitor);
}
pub fn use_fn_args(&self,
_: NodeId,
arg_exprs: &[@expr],
- visitor: vt<VisitContext>) {
+ visitor: ComputeModesVisitor) {
//! Uses the argument expressions.
for arg_expr in arg_exprs.iter() {
self.use_fn_arg(*arg_expr, visitor);
}
}
- pub fn use_fn_arg(&self, arg_expr: @expr, visitor: vt<VisitContext>) {
+ pub fn use_fn_arg(&self, arg_expr: @expr, visitor: ComputeModesVisitor) {
//! Uses the argument.
self.consume_expr(arg_expr, visitor)
}
pub enum SelfBinding {
NoSelfBinding,
- HasSelfBinding(NodeId, bool /* is implicit */)
+ HasSelfBinding(NodeId)
}
struct ResolveVisitor {
trait_map: HashMap::new(),
used_imports: HashSet::new(),
+ emit_errors: true,
intr: session.intr()
};
export_map2: ExportMap2,
trait_map: TraitMap,
+ // 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,
+
used_imports: HashSet<NodeId>,
}
// Return an error here by looking up the namespace that
// had the duplicate.
let ns = ns.unwrap();
- self.session.span_err(sp,
+ self.resolve_error(sp,
fmt!("duplicate definition of %s `%s`",
namespace_error_to_str(duplicate_type),
self.session.str_of(name)));
self.import_path_to_str(
import_directive.module_path,
*import_directive.subclass));
- self.session.span_err(import_directive.span, msg);
+ self.resolve_error(import_directive.span, msg);
}
Indeterminate => {
// Bail out. We'll come around next time.
// We need to resolve both namespaces for this to succeed.
//
- // FIXME #4949: See if there's some way of handling namespaces in
- // a more generic way. We have two of them; it seems worth
- // doing...
let mut value_result = UnknownResult;
let mut type_result = UnknownResult;
let span = directive.span;
if resolve_fail {
- self.session.span_err(span, fmt!("unresolved import: there is no `%s` in `%s`",
+ self.resolve_error(span, fmt!("unresolved import: there is no `%s` in `%s`",
self.session.str_of(source),
self.module_to_str(containing_module)));
return Failed;
} else if priv_fail {
- self.session.span_err(span, fmt!("unresolved import: found `%s` in `%s` but it is \
+ self.resolve_error(span, fmt!("unresolved import: found `%s` in `%s` but it is \
private", self.session.str_of(source),
self.module_to_str(containing_module)));
return Failed;
hi: span.lo + BytePos(segment_name.len()),
expn_info: span.expn_info,
};
- self.session.span_err(span,
+ self.resolve_error(span,
fmt!("unresolved import. maybe \
a missing `extern mod \
%s`?",
segment_name));
return Failed;
}
- self.session.span_err(span, fmt!("unresolved import: could not find `%s` in \
+ self.resolve_error(span, fmt!("unresolved import: could not find `%s` in \
`%s`.", segment_name, module_name));
return Failed;
}
match type_def.module_def {
None => {
// Not a module.
- self.session.span_err(span,
+ self.resolve_error(span,
fmt!("not a \
module `%s`",
self.session.
module_def.kind) {
(ImportSearch, TraitModuleKind) |
(ImportSearch, ImplModuleKind) => {
- self.session.span_err(
+ self.resolve_error(
span,
"cannot import from a trait \
or type implementation");
}
None => {
// There are no type bindings at all.
- self.session.span_err(span,
+ self.resolve_error(span,
fmt!("not a module `%s`",
self.session.str_of(
name)));
let mpath = self.idents_to_str(module_path);
match mpath.rfind(':') {
Some(idx) => {
- self.session.span_err(span, fmt!("unresolved import: could not find `%s` \
+ self.resolve_error(span, fmt!("unresolved import: could not find `%s` \
in `%s`",
// idx +- 1 to account for the colons
// on either side
module_path[0]);
match result {
Failed => {
- self.session.span_err(span,
- "unresolved name");
+ self.resolve_error(span, "unresolved name");
return Failed;
}
Indeterminate => {
if index != import_count {
let sn = self.session.codemap.span_to_snippet(imports[index].span).unwrap();
if sn.contains("::") {
- self.session.span_err(imports[index].span, "unresolved import");
+ self.resolve_error(imports[index].span, "unresolved import");
} else {
let err = fmt!("unresolved import (maybe you meant `%s::*`?)",
sn.slice(0, sn.len()));
- self.session.span_err(imports[index].span, err);
+ self.resolve_error(imports[index].span, err);
}
}
// named function item. This is not allowed, so we
// report an error.
- self.session.span_err(
+ self.resolve_error(
span,
"can't capture dynamic environment in a fn item; \
use the || { ... } closure form instead");
// This was an attempt to use a type parameter outside
// its scope.
- self.session.span_err(span,
+ self.resolve_error(span,
"attempt to use a type \
argument out of scope");
}
// named function item. This is not allowed, so we
// report an error.
- self.session.span_err(
+ self.resolve_error(
span,
"can't capture dynamic environment in a fn item; \
use the || { ... } closure form instead");
// This was an attempt to use a type parameter outside
// its scope.
- self.session.span_err(span,
+ self.resolve_error(span,
"attempt to use a type \
argument out of scope");
}
}
ConstantItemRibKind => {
// Still doesn't deal with upvars
- self.session.span_err(span,
+ self.resolve_error(span,
"attempt to use a non-constant \
value in a constant");
NoSelfBinding => {
// Nothing to do.
}
- HasSelfBinding(self_node_id, is_implicit) => {
- let def_like = dl_def(def_self(self_node_id,
- is_implicit));
+ HasSelfBinding(self_node_id) => {
+ let def_like = dl_def(def_self(self_node_id));
*function_value_rib.self_binding = Some(def_like);
}
}
};
let msg = fmt!("attempt to %s a nonexistent trait `%s`", usage_str, path_str);
- self.session.span_err(trait_reference.path.span, msg);
+ self.resolve_error(trait_reference.path.span, msg);
}
Some(def) => {
debug!("(resolving trait) found trait def: %?", def);
match ident_map.find(&ident) {
Some(&prev_field) => {
let ident_str = self.session.str_of(ident);
- self.session.span_err(field.span,
+ self.resolve_error(field.span,
fmt!("field `%s` is already declared", ident_str));
self.session.span_note(prev_field.span,
"Previously declared here");
// we only have self ty if it is a non static method
let self_binding = match method.explicit_self.node {
sty_static => { NoSelfBinding }
- _ => { HasSelfBinding(method.self_id, false) }
+ _ => { HasSelfBinding(method.self_id) }
};
self.resolve_function(rib_kind,
for (&key, &binding_0) in map_0.iter() {
match map_i.find(&key) {
None => {
- self.session.span_err(
+ self.resolve_error(
p.span,
fmt!("variable `%s` from pattern #1 is \
not bound in pattern #%u",
}
Some(binding_i) => {
if binding_0.binding_mode != binding_i.binding_mode {
- self.session.span_err(
+ self.resolve_error(
binding_i.span,
fmt!("variable `%s` is bound with different \
mode in pattern #%u than in pattern #1",
for (&key, &binding) in map_i.iter() {
if !map_0.contains_key(&key) {
- self.session.span_err(
+ self.resolve_error(
binding.span,
fmt!("variable `%s` from pattern #%u is \
not bound in pattern #1",
self.record_def(path_id, def);
}
None => {
- self.session.span_err
+ self.resolve_error
(ty.span, fmt!("use of undeclared type name `%s`",
self.idents_to_str(path.idents)));
}
self.record_def(pattern.id, def);
}
FoundStructOrEnumVariant(_) => {
- self.session.span_err(pattern.span,
+ self.resolve_error(pattern.span,
fmt!("declaration of `%s` \
shadows an enum \
variant or unit-like \
self.record_def(pattern.id, def);
}
FoundConst(_) => {
- self.session.span_err(pattern.span,
+ self.resolve_error(pattern.span,
"only refutable patterns \
allowed here");
}
// Then this is a duplicate variable
// in the same disjunct, which is an
// error
- self.session.span_err(pattern.span,
+ self.resolve_error(pattern.span,
fmt!("Identifier `%s` is bound more \
than once in the same pattern",
path_to_str(path, self.session
self.record_def(pattern.id, def);
}
Some(_) => {
- self.session.span_err(
+ self.resolve_error(
path.span,
fmt!("`%s` is not an enum variant or constant",
self.session.str_of(
*path.idents.last())));
}
None => {
- self.session.span_err(path.span,
+ self.resolve_error(path.span,
"unresolved enum variant");
}
}
self.record_def(pattern.id, def);
}
Some(_) => {
- self.session.span_err(
+ self.resolve_error(
path.span,
fmt!("`%s` is not an enum variant, struct or const",
self.session.str_of(
*path.idents.last())));
}
None => {
- self.session.span_err(path.span,
+ self.resolve_error(path.span,
"unresolved enum variant, \
struct or const");
}
result => {
debug!("(resolving pattern) didn't find struct \
def: %?", result);
- self.session.span_err(
+ self.resolve_error(
path.span,
fmt!("`%s` does not name a structure",
self.idents_to_str(path.idents)));
path.span,
PathPublicOnlySearch) {
Failed => {
- self.session.span_err(path.span,
+ self.resolve_error(path.span,
fmt!("use of undeclared module `%s`",
self.idents_to_str(
module_path_idents)));
path.span,
PathPublicOrPrivateSearch) {
Failed => {
- self.session.span_err(path.span,
+ self.resolve_error(path.span,
fmt!("use of undeclared module `::%s`",
self.idents_to_str(
module_path_idents)));
DontAllowCapturingSelf) {
Some(dl_def(def)) => return Some(def),
_ => {
- self.session.span_bug(span,
- "self wasn't mapped to a \
- def?!")
+ if self.session.has_errors() {
+ // May happen inside a nested fn item, cf #6642.
+ return None;
+ } else {
+ self.session.span_bug(span,
+ "self wasn't mapped to a def?!")
+ }
}
}
}
}
}
+ fn with_no_errors<T>(@mut self, f: &fn() -> T) -> T {
+ self.emit_errors = false;
+ let rs = f();
+ self.emit_errors = true;
+ rs
+ }
+
+ fn resolve_error(@mut self, span: span, s: &str) {
+ if self.emit_errors {
+ self.session.span_err(span, s);
+ }
+ }
+
pub fn find_best_match_for_name(@mut self,
name: &str,
max_distance: uint)
// out here.
match def {
def_method(*) => {
- self.session.span_err(expr.span,
+ self.resolve_error(expr.span,
"first-class methods \
are not supported");
self.session.span_note(expr.span,
let wrong_name = self.idents_to_str(
path.idents);
if self.name_exists_in_scope_struct(wrong_name) {
- self.session.span_err(expr.span,
+ self.resolve_error(expr.span,
fmt!("unresolved name `%s`. \
Did you mean `self.%s`?",
wrong_name,
wrong_name));
}
else {
- // limit search to 5 to reduce the number
- // of stupid suggestions
- match self.find_best_match_for_name(wrong_name, 5) {
- Some(m) => {
- self.session.span_err(expr.span,
- fmt!("unresolved name `%s`. \
- Did you mean `%s`?",
- wrong_name, m));
- }
- None => {
- self.session.span_err(expr.span,
- fmt!("unresolved name `%s`.",
- wrong_name));
+ // 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.)
+ match self.with_no_errors(||
+ self.resolve_path(expr.id, path, TypeNS, false, visitor)) {
+ Some(def_ty(struct_id))
+ if self.structs.contains(&struct_id) => {
+ self.resolve_error(expr.span,
+ fmt!("`%s` is a structure name, but this expression \
+ uses it like a function name", wrong_name));
+
+ self.session.span_note(expr.span, fmt!("Did you mean to write: \
+ `%s { /* fields */ }`?", wrong_name));
+
}
+ _ =>
+ // limit search to 5 to reduce the number
+ // of stupid suggestions
+ match self.find_best_match_for_name(wrong_name, 5) {
+ Some(m) => {
+ self.resolve_error(expr.span,
+ fmt!("unresolved name `%s`. \
+ Did you mean `%s`?",
+ wrong_name, m));
+ }
+ None => {
+ self.resolve_error(expr.span,
+ fmt!("unresolved name `%s`.",
+ wrong_name));
+ }
+ }
}
}
}
result => {
debug!("(resolving expression) didn't find struct \
def: %?", result);
- self.session.span_err(
+ self.resolve_error(
path.span,
fmt!("`%s` does not name a structure",
self.idents_to_str(path.idents)));
match self.search_ribs(self.label_ribs, label, expr.span,
DontAllowCapturingSelf) {
None =>
- self.session.span_err(expr.span,
+ self.resolve_error(expr.span,
fmt!("use of undeclared label \
`%s`",
self.session.str_of(
expr_self => {
match self.resolve_self_value_in_local_ribs(expr.span) {
None => {
- self.session.span_err(expr.span,
+ self.resolve_error(expr.span,
"`self` is not allowed in \
this context")
}
match pat_binding_mode {
bind_infer => {}
bind_by_ref(*) => {
- self.session.span_err(
+ self.resolve_error(
pat.span,
fmt!("cannot use `ref` binding mode with %s",
descr));
dest.to_str(bcx.ccx()));
let _indenter = indenter();
- debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
+ debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
let dest = {
if ty::type_is_voidish(ty) {
debug!("trans_to_datum_unadjusted(expr=%s)", bcx.expr_to_str(expr));
let _indenter = indenter();
- debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
+ debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) {
ty::LvalueExpr => {
return bcx;
}
}
- ast::def_struct(*) => {
+ ast::def_struct(def_id) => {
let ty = expr_ty(bcx, ref_expr);
match ty::get(ty).sty {
ty::ty_struct(did, _) if ty::has_dtor(ccx.tcx, did) => {
let repr = adt::represent_type(ccx, ty);
adt::trans_start_init(bcx, repr, lldest, 0);
}
- _ => {}
+ ty::ty_bare_fn(*) => {
+ let fn_data = callee::trans_fn_ref(bcx, def_id, ref_expr.id);
+ Store(bcx, fn_data.llfn, lldest);
+ }
+ _ => ()
}
return bcx;
}
{
let _icx = push_ctxt("trans_def_datum_unadjusted");
- match def {
+ let fn_data = match def {
ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
- let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
- return fn_data_to_datum(bcx, ref_expr, did, fn_data);
+ callee::trans_fn_ref(bcx, did, ref_expr.id)
}
ast::def_static_method(impl_did, Some(trait_did), _) => {
- let fn_data = meth::trans_static_method_callee(bcx, impl_did,
- trait_did,
- ref_expr.id);
- return fn_data_to_datum(bcx, ref_expr, impl_did, fn_data);
+ meth::trans_static_method_callee(bcx, impl_did,
+ trait_did,
+ ref_expr.id)
}
_ => {
bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
"Non-DPS def %? referened by %s",
def, bcx.node_id_to_str(ref_expr.id)));
}
- }
+ };
- fn fn_data_to_datum(bcx: @mut Block,
- ref_expr: &ast::expr,
- def_id: ast::def_id,
- fn_data: callee::FnData) -> DatumBlock {
- /*!
- *
- * Translates a reference to a top-level fn item into a rust
- * value. This is just a fn pointer.
- */
-
- let is_extern = {
- let fn_tpt = ty::lookup_item_type(bcx.tcx(), def_id);
- ty::ty_fn_purity(fn_tpt.ty) == ast::extern_fn
- };
- let (rust_ty, llval) = if is_extern {
- let rust_ty = ty::mk_ptr(
- bcx.tcx(),
- ty::mt {
- ty: ty::mk_mach_uint(ast::ty_u8),
- mutbl: ast::m_imm
- }); // *u8
- (rust_ty, PointerCast(bcx, fn_data.llfn, Type::i8p()))
- } else {
- let fn_ty = expr_ty(bcx, ref_expr);
- (fn_ty, fn_data.llfn)
- };
- return DatumBlock {
- bcx: bcx,
- datum: Datum {val: llval,
- ty: rust_ty,
- mode: ByValue}
- };
+ let fn_ty = expr_ty(bcx, ref_expr);
+ DatumBlock {
+ bcx: bcx,
+ datum: Datum {
+ val: fn_data.llfn,
+ ty: fn_ty,
+ mode: ByValue
+ }
}
}
ast::def_local(nid, _) | ast::def_binding(nid, _) => {
take_local(bcx, bcx.fcx.lllocals, nid)
}
- ast::def_self(nid, _) => {
+ ast::def_self(nid) => {
let self_info: ValSelfData = match bcx.fcx.llself {
Some(ref self_info) => *self_info,
None => {
pub fn with_field_tys<R>(tcx: ty::ctxt,
ty: ty::t,
node_id_opt: Option<ast::NodeId>,
- op: &fn(uint, (&[ty::field])) -> R) -> R {
+ op: &fn(ty::Disr, (&[ty::field])) -> R) -> R {
match ty::get(ty).sty {
ty::ty_struct(did, ref substs) => {
op(0, struct_fields(tcx, did, substs))
* - `optbase` contains information on the base struct (if any) from
* which remaining fields are copied; see comments on `StructBaseInfo`.
*/
-fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: uint,
+fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: ty::Disr,
fields: &[(uint, @ast::expr)],
optbase: Option<StructBaseInfo>,
dest: Dest) -> @mut Block {
ty::ty_float(*) => cast_float,
ty::ty_ptr(*) => cast_pointer,
ty::ty_rptr(*) => cast_pointer,
+ ty::ty_bare_fn(*) => cast_pointer,
ty::ty_int(*) => cast_integral,
ty::ty_uint(*) => cast_integral,
ty::ty_bool => cast_integral,
val_ty(lldiscrim_a),
lldiscrim_a, true),
cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
- _ => ccx.sess.bug("translating unsupported cast.")
+ _ => ccx.sess.bug(fmt!("translating unsupported cast: \
+ %s (%?) -> %s (%?)",
+ t_in.repr(ccx.tcx), k_in,
+ t_out.repr(ccx.tcx), k_out))
}
}
- _ => ccx.sess.bug("translating unsupported cast.")
+ _ => ccx.sess.bug(fmt!("translating unsupported cast: \
+ %s (%?) -> %s (%?)",
+ t_in.repr(ccx.tcx), k_in,
+ t_out.repr(ccx.tcx), k_out))
};
return immediate_rvalue_bcx(bcx, newval, t_out);
}
use middle::lint::unreachable_code;
use middle::ty::{FnSig, VariantInfo};
use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
-use middle::ty::{substs, param_ty, ExprTyProvider};
+use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
use middle::ty;
use middle::typeck::astconv::AstConv;
use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
let rty = ty::node_id_to_type(ccx.tcx, id);
let mut variants: ~[@ty::VariantInfo] = ~[];
- let mut disr_vals: ~[uint] = ~[];
- let mut prev_disr_val: Option<uint> = None;
+ let mut disr_vals: ~[ty::Disr] = ~[];
+ let mut prev_disr_val: Option<ty::Disr> = None;
for v in vs.iter() {
// handle, so we may still get an internal compiler error
match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
- Ok(const_eval::const_int(val)) => current_disr_val = val as uint,
- Ok(const_eval::const_uint(val)) => current_disr_val = val as uint,
+ Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
+ Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
Ok(_) => {
ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
}
sp: span,
defn: ast::def)
-> ty_param_bounds_and_ty {
-
match defn {
- ast::def_arg(nid, _) | ast::def_local(nid, _) | ast::def_self(nid, _) |
+ ast::def_arg(nid, _) | ast::def_local(nid, _) | ast::def_self(nid) |
ast::def_binding(nid, _) => {
let typ = fcx.local_ty(sp, nid);
return no_params(typ);
}
- ast::def_fn(_, ast::extern_fn) => {
- // extern functions are just u8 pointers
- return ty_param_bounds_and_ty {
- generics: ty::Generics {
- type_param_defs: @~[],
- region_param: None
- },
- ty: ty::mk_ptr(
- fcx.ccx.tcx,
- ty::mt {
- ty: ty::mk_mach_uint(ast::ty_u8),
- mutbl: ast::m_imm
- })
- };
- }
-
ast::def_fn(id, _) | ast::def_static_method(id, _, _) |
ast::def_static(id, _) | ast::def_variant(_, id) |
ast::def_struct(id) => {
let ty_param_count = tpt.generics.type_param_defs.len();
let ty_substs_len = pth.types.len();
- debug!("ty_param_count=%? ty_substs_len=%?",
+ debug!("tpt=%s ty_param_count=%? ty_substs_len=%?",
+ tpt.repr(fcx.tcx()),
ty_param_count,
ty_substs_len);