/******************************************************************************* * Copyright (c) 2009-2013 CWI * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI *******************************************************************************/ package org.rascalmpl.interpreter.types; import java.util.HashSet; import java.util.Set; import org.rascalmpl.interpreter.env.Environment; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; public class TypeReachability { public static boolean mayOccurIn(Type small, Type large, Environment env) { return mayOccurIn(small, large, new HashSet<Type>(), env); } static private boolean mayOccurIn(final Type small, final Type large, final Set<Type> seen, final Environment env) { // TODO: this should probably be a visitor as well if (small.isBottom() && !large.isBottom()) { return false; } if (small.comparable(large)) { return true; } return large.accept(new DefaultRascalTypeVisitor<Boolean, RuntimeException>(false) { @Override public Boolean visitList(Type type) { return mayOccurIn(small, large.getElementType(), seen, env); } @Override public Boolean visitSet(Type type) { return mayOccurIn(small, large.getElementType(), seen, env); } @Override public Boolean visitMap(Type type) { return mayOccurIn(small, large.getKeyType(), seen, env) || mayOccurIn(small, large.getValueType(), seen, env); } @Override public Boolean visitTuple(Type type) { for (int i = 0; i < large.getArity(); i++) { if (mayOccurIn(small, large.getFieldType(i), seen, env)) { return true; } } return false; } @Override public Boolean visitFunction(RascalType type) { return false; } @Override public Boolean visitOverloadedFunction(RascalType type) throws RuntimeException { return false; } @Override public Boolean visitReified(RascalType type) throws RuntimeException { // TODO: we can be more precise here because we know only Symbols and Definitions can occur in // reified types return true; } @Override public Boolean visitNonTerminal(RascalType type) throws RuntimeException { // TODO: Until we have more precise info about the types in the // concrete syntax // we just return true here. return true; } @Override public Boolean visitConstructor(Type type) { for (int i = 0; i < type.getArity(); i++) { if (mayOccurIn(small, type.getFieldType(i), seen, env)) { return true; } } return false; } @Override public Boolean visitAbstractData(Type type) { if (small.equivalent(TypeFactory.getInstance().nodeType())) { return true; } seen.add(large); for (Type alt : env.lookupAlternatives(large)) { for (int i = 0; i < alt.getArity(); i++) { Type fType = alt.getFieldType(i); if (seen.add(fType) && mayOccurIn(small, fType, seen, env)) { return true; } } } return false; } }); } }