/* * #%~ * The VDM Type Checker * %% * Copyright (C) 2008 - 2014 Overture * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.typechecker.visitor; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.analysis.intf.IQuestionAnswer; import org.overture.ast.definitions.PDefinition; import org.overture.ast.factory.AstFactory; import org.overture.ast.patterns.ANamePatternPair; import org.overture.ast.patterns.AObjectPattern; import org.overture.ast.patterns.ASeqMultipleBind; import org.overture.ast.patterns.ASetMultipleBind; import org.overture.ast.patterns.ATypeMultipleBind; import org.overture.ast.typechecker.NameScope; import org.overture.ast.types.AClassType; import org.overture.ast.types.SSeqType; import org.overture.ast.types.SSetType; import org.overture.ast.types.PType; import org.overture.typechecker.TypeCheckInfo; import org.overture.typechecker.TypeCheckerErrors; import org.overture.typechecker.assistant.type.PTypeAssistantTC; public class TypeCheckerPatternVisitor extends AbstractTypeCheckVisitor { public TypeCheckerPatternVisitor( IQuestionAnswer<TypeCheckInfo, PType> typeCheckVisitor) { super(typeCheckVisitor); } @Override public PType caseASetMultipleBind(ASetMultipleBind node, TypeCheckInfo question) throws AnalysisException { question.assistantFactory.createPPatternListAssistant().typeResolve(node.getPlist(), THIS, question); question.qualifiers = null; PType type = node.getSet().apply(THIS, question); PType result = AstFactory.newAUnknownType(node.getLocation()); if (!question.assistantFactory.createPTypeAssistant().isSet(type)) { TypeCheckerErrors.report(3197, "Expression matching set bind is not a set", node.getSet().getLocation(), node.getSet()); TypeCheckerErrors.detail("Actual type", type); } else { SSetType st = question.assistantFactory.createPTypeAssistant().getSet(type); if (!st.getEmpty()) { result = st.getSetof(); PType ptype = question.assistantFactory.createPMultipleBindAssistant().getPossibleType(node); if (!question.assistantFactory.getTypeComparator().compatible(ptype, result)) { TypeCheckerErrors.report(3264, "At least one bind cannot match set", node.getSet().getLocation(), node.getSet()); TypeCheckerErrors.detail2("Binds", ptype, "Set of", st); } } else { TypeCheckerErrors.warning(5009, "Empty set used in bind", node.getSet().getLocation(), node.getSet()); } } return result; } @Override public PType caseASeqMultipleBind(ASeqMultipleBind node, TypeCheckInfo question) throws AnalysisException { question.assistantFactory.createPPatternListAssistant().typeResolve(node.getPlist(), THIS, question); question.qualifiers = null; PType type = node.getSeq().apply(THIS, question); PType result = AstFactory.newAUnknownType(node.getLocation()); if (!question.assistantFactory.createPTypeAssistant().isSeq(type)) { TypeCheckerErrors.report(3197, "Expression matching seq bind is not a sequence", node.getSeq().getLocation(), node.getSeq()); TypeCheckerErrors.detail("Actual type", type); } else { SSeqType st = question.assistantFactory.createPTypeAssistant().getSeq(type); if (!st.getEmpty()) { result = st.getSeqof(); PType ptype = question.assistantFactory.createPMultipleBindAssistant().getPossibleType(node); if (!question.assistantFactory.getTypeComparator().compatible(ptype, result)) { TypeCheckerErrors.report(3264, "At least one bind cannot match sequence", node.getSeq().getLocation(), node.getSeq()); TypeCheckerErrors.detail2("Binds", ptype, "Seq of", st); } } else { TypeCheckerErrors.warning(5009, "Empty squence used in bind", node.getSeq().getLocation(), node.getSeq()); } } return result; } @Override public PType caseATypeMultipleBind(ATypeMultipleBind node, TypeCheckInfo question) throws AnalysisException { question.assistantFactory.createPPatternListAssistant().typeResolve(node.getPlist(), THIS, question); PType type = question.assistantFactory.createPTypeAssistant().typeResolve(node.getType(), null, THIS, question); PType ptype = question.assistantFactory.createPPatternListAssistant().getPossibleType(node.getPlist(), node.getLocation()); if (!question.assistantFactory.getTypeComparator().compatible(ptype, type)) { TypeCheckerErrors.report(3265, "At least one bind cannot match this type", type.getLocation(), type); TypeCheckerErrors.detail2("Binds", ptype, "Type", type); } node.setType(type); return type; } @Override public PType caseAObjectPattern(AObjectPattern pattern, TypeCheckInfo question) throws AnalysisException { PTypeAssistantTC typeAssistant = question.assistantFactory.createPTypeAssistant(); if (!typeAssistant.isClass(pattern.getType(), question.env)) { TypeCheckerErrors.report(3331, "obj_ expression is not an object type", pattern.getLocation(), pattern); TypeCheckerErrors.detail("Type", pattern.getType()); } else { // Check whether the field access is permitted from here. AClassType cls = typeAssistant.getClassType(pattern.getType(), question.env); for (ANamePatternPair npp: pattern.getFields()) { PDefinition fdef = question.assistantFactory.createAClassTypeAssistant().findName(cls, npp.getName(), NameScope.STATE); if (fdef == null) { TypeCheckerErrors.report(3091, "Unknown member " + npp.getName() + " of class " + cls.getName().getName(), npp.getName().getLocation(), npp.getName()); } else if (!question.assistantFactory.createSClassDefinitionAssistant().isAccessible(question.env, fdef, false)) { TypeCheckerErrors.report(3092, "Inaccessible member " + npp.getName() + " of class " + cls.getName().getName(), npp.getName().getLocation(), npp.getName()); } } if (question.env.isFunctional()) { TypeCheckerErrors.report(3332, "Object pattern cannot be used from a function", pattern.getLocation(), pattern); } } return pattern.getType(); } }