rustc: Add some more checks to coherence
This commit is contained in:
parent
1806707dcb
commit
e51f259ff0
@ -11,16 +11,20 @@ import middle::ty::{ty_fn, ty_trait, ty_tup, ty_var, ty_var_integral};
|
||||
import middle::ty::{ty_param, ty_self, ty_constr, ty_type, ty_opaque_box};
|
||||
import middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, new_ty_hash};
|
||||
import middle::ty::{subst};
|
||||
import middle::typeck::infer::{infer_ctxt, mk_eqty, new_infer_ctxt};
|
||||
import syntax::ast::{crate, def_id, item, item_impl, method, region_param};
|
||||
import syntax::ast::{trait_ref};
|
||||
import middle::typeck::infer::{infer_ctxt, mk_subty, new_infer_ctxt};
|
||||
import syntax::ast::{crate, def_id, item, item_class, item_const, item_enum};
|
||||
import syntax::ast::{item_fn, item_foreign_mod, item_impl, item_mac};
|
||||
import syntax::ast::{item_mod, item_trait, item_ty, local_crate, method};
|
||||
import syntax::ast::{node_id, region_param, rp_none, rp_self, trait_ref};
|
||||
import syntax::ast_util::{def_id_of_def, new_def_hash};
|
||||
import syntax::visit::{default_simple_visitor, mk_simple_visitor};
|
||||
import syntax::visit::{visit_crate};
|
||||
import syntax::visit::{default_simple_visitor, default_visitor};
|
||||
import syntax::visit::{mk_simple_visitor, mk_vt, visit_crate, visit_item};
|
||||
import syntax::visit::{visit_mod};
|
||||
import util::ppaux::ty_to_str;
|
||||
|
||||
import dvec::{dvec, extensions};
|
||||
import result::{extensions};
|
||||
import std::map::hashmap;
|
||||
import std::map::{hashmap, int_hash};
|
||||
import uint::range;
|
||||
|
||||
class CoherenceInfo {
|
||||
@ -43,10 +47,26 @@ class CoherenceChecker {
|
||||
let inference_context: infer_ctxt;
|
||||
let info: @CoherenceInfo;
|
||||
|
||||
// A mapping from implementations to the corresponding base type
|
||||
// definition ID.
|
||||
let base_type_def_ids: hashmap<node_id,def_id>;
|
||||
|
||||
// A set of implementations in privileged scopes; i.e. those
|
||||
// implementations that are defined in the same scope as their base types.
|
||||
let privileged_implementations: hashmap<node_id,()>;
|
||||
|
||||
// The set of types that we are currently in the privileged scope of. This
|
||||
// is used while we traverse the AST while checking privileged scopes.
|
||||
let privileged_types: hashmap<def_id,()>;
|
||||
|
||||
new(crate_context: @crate_ctxt) {
|
||||
self.crate_context = crate_context;
|
||||
self.inference_context = new_infer_ctxt(crate_context.tcx);
|
||||
self.info = @CoherenceInfo();
|
||||
|
||||
self.base_type_def_ids = int_hash();
|
||||
self.privileged_implementations = int_hash();
|
||||
self.privileged_types = new_def_hash();
|
||||
}
|
||||
|
||||
fn check_coherence(crate: @crate) {
|
||||
@ -71,6 +91,9 @@ class CoherenceChecker {
|
||||
for self.info.extension_methods.each |def_id, items| {
|
||||
self.check_implementation_coherence(def_id, items);
|
||||
}
|
||||
|
||||
// Check whether traits with base types are in privileged scopes.
|
||||
self.check_privileged_scopes(crate);
|
||||
}
|
||||
|
||||
fn check_implementation(item: @item,
|
||||
@ -121,6 +144,17 @@ class CoherenceChecker {
|
||||
implementation_list.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the implementation to the mapping from implementation to base
|
||||
// type def ID, if there is a base type for this implementation.
|
||||
alt self.get_base_type_def_id(self_type.ty) {
|
||||
none {
|
||||
// Nothing to do.
|
||||
}
|
||||
some(base_type_def_id) {
|
||||
self.base_type_def_ids.insert(item.id, base_type_def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_base_type(original_type: t) -> option<t> {
|
||||
@ -147,6 +181,26 @@ class CoherenceChecker {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the def ID of the base type.
|
||||
fn get_base_type_def_id(original_type: t) -> option<def_id> {
|
||||
alt self.get_base_type(original_type) {
|
||||
none {
|
||||
ret none;
|
||||
}
|
||||
some(base_type) {
|
||||
alt get(base_type).struct {
|
||||
ty_enum(def_id, _) | ty_class(def_id, _) {
|
||||
ret some(def_id);
|
||||
}
|
||||
_ {
|
||||
fail "get_base_type() returned a type that wasn't an \
|
||||
enum or class";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_implementation_coherence(_trait_def_id: def_id,
|
||||
implementations: @dvec<@item>) {
|
||||
|
||||
@ -177,7 +231,8 @@ class CoherenceChecker {
|
||||
|
||||
let monotype_a = self.universally_quantify_polytype(polytype_a);
|
||||
let monotype_b = self.universally_quantify_polytype(polytype_b);
|
||||
ret mk_eqty(self.inference_context, monotype_a, monotype_b).is_ok();
|
||||
ret mk_subty(self.inference_context, monotype_a, monotype_b).is_ok()
|
||||
|| mk_subty(self.inference_context, monotype_b, monotype_a).is_ok();
|
||||
}
|
||||
|
||||
// Converts a polytype to a monotype by replacing all parameters with
|
||||
@ -185,10 +240,10 @@ class CoherenceChecker {
|
||||
fn universally_quantify_polytype(polytype: ty_param_bounds_and_ty) -> t {
|
||||
let self_region;
|
||||
alt polytype.rp {
|
||||
ast::rp_none {
|
||||
rp_none {
|
||||
self_region = none;
|
||||
}
|
||||
ast::rp_self {
|
||||
rp_self {
|
||||
self_region = some(self.inference_context.next_region_var())
|
||||
}
|
||||
};
|
||||
@ -220,6 +275,139 @@ class CoherenceChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Privileged scope checking
|
||||
|
||||
fn check_privileged_scopes(crate: @crate) {
|
||||
visit_crate(*crate, (), mk_vt(@{
|
||||
visit_item: |item, _context, visitor| {
|
||||
alt item.node {
|
||||
item_mod(module) {
|
||||
// First, gather up all privileged types.
|
||||
let privileged_types =
|
||||
self.gather_privileged_types(module.items);
|
||||
for privileged_types.each |privileged_type| {
|
||||
#debug("(checking privileged scopes) entering \
|
||||
privileged scope of %d:%d",
|
||||
privileged_type.crate,
|
||||
privileged_type.node);
|
||||
|
||||
self.privileged_types.insert(privileged_type, ());
|
||||
}
|
||||
|
||||
// Then visit the module items.
|
||||
visit_mod(module, item.span, item.id, (), visitor);
|
||||
|
||||
// Finally, remove privileged types from the map.
|
||||
for privileged_types.each |privileged_type| {
|
||||
self.privileged_types.remove(privileged_type);
|
||||
}
|
||||
}
|
||||
item_impl(_, _, optional_trait_ref, _, _) {
|
||||
alt self.base_type_def_ids.find(item.id) {
|
||||
none {
|
||||
// Nothing to do.
|
||||
}
|
||||
some(base_type_def_id) {
|
||||
// Check to see whether the implementation is
|
||||
// in the scope of its base type.
|
||||
|
||||
let privileged_types = &self.privileged_types;
|
||||
if privileged_types.
|
||||
contains_key(base_type_def_id) {
|
||||
|
||||
// Record that this implementation is OK.
|
||||
self.privileged_implementations.insert
|
||||
(item.id, ());
|
||||
} else {
|
||||
// This implementation is not in scope of
|
||||
// its base type. This still might be OK
|
||||
// if the trait is defined in the same
|
||||
// crate.
|
||||
|
||||
alt optional_trait_ref {
|
||||
none {
|
||||
// There is no trait to implement,
|
||||
// so this is an error.
|
||||
|
||||
let session =
|
||||
self.crate_context.tcx.sess;
|
||||
session.span_warn(item.span,
|
||||
"cannot \
|
||||
implement \
|
||||
inherent \
|
||||
methods for a \
|
||||
type outside \
|
||||
the scope the \
|
||||
type was \
|
||||
defined in; \
|
||||
define and \
|
||||
implement a \
|
||||
trait \
|
||||
instead");
|
||||
}
|
||||
some(trait_ref) {
|
||||
// This is OK if and only if the
|
||||
// trait was defined in this
|
||||
// crate.
|
||||
|
||||
let def_map = self.crate_context
|
||||
.tcx.def_map;
|
||||
let trait_def =
|
||||
def_map.get(trait_ref.id);
|
||||
let trait_id =
|
||||
def_id_of_def(trait_def);
|
||||
if trait_id.crate != local_crate {
|
||||
let session = self
|
||||
.crate_context.tcx.sess;
|
||||
session.span_warn(item.span,
|
||||
"cannot \
|
||||
provide \
|
||||
an \
|
||||
extension \
|
||||
implement\
|
||||
ation \
|
||||
for a \
|
||||
trait not \
|
||||
defined \
|
||||
in this \
|
||||
crate");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visit_item(item, (), visitor);
|
||||
}
|
||||
_ {
|
||||
visit_item(item, (), visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
with *default_visitor()
|
||||
}));
|
||||
}
|
||||
|
||||
fn gather_privileged_types(items: ~[@item]) -> @dvec<def_id> {
|
||||
let results = @dvec();
|
||||
for items.each |item| {
|
||||
alt item.node {
|
||||
item_class(*) | item_enum(*) {
|
||||
results.push(local_def(item.id));
|
||||
}
|
||||
|
||||
item_const(*) | item_fn(*) | item_mod(*) |
|
||||
item_foreign_mod(*) | item_ty(*) | item_trait(*) |
|
||||
item_impl(*) | item_mac(*) {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret results;
|
||||
}
|
||||
}
|
||||
|
||||
fn check_coherence(crate_context: @crate_ctxt, crate: @crate) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user