/** * Copyright (c) 2009-2011, The HATS Consortium. All rights reserved. * This file is licensed under the terms of the Modified BSD License. */ package abs.frontend.typechecker.locationtypes; import java.util.Map; import abs.frontend.analyser.ErrorMessage; import abs.frontend.analyser.TypeError; import abs.frontend.ast.*; import abs.frontend.typechecker.Type; import abs.frontend.typechecker.TypeAnnotation; import abs.frontend.typechecker.ext.DefaultTypeSystemExtension; import abs.frontend.typechecker.ext.AdaptDirection; import abs.frontend.typechecker.locationtypes.infer.LocationTypeInferrerExtension; import abs.frontend.typechecker.locationtypes.infer.LocationTypeVariable; public class LocationTypeExtension extends DefaultTypeSystemExtension { private LocationType defaultType = LocationType.SOMEWHERE; private LocationTypeInferrerExtension ltie; public LocationTypeExtension(Model m) { super(m); } public LocationTypeExtension(Model m, LocationTypeInferrerExtension ltie) { super(m); this.ltie = ltie; defaultType = ltie.getDefaultType(); } @Override public void checkAssignable(Type adaptTo, AdaptDirection dir, Type rht, Type lht, ASTNode<?> n) { LocationType rhtl = getLocationType(rht); LocationType lhtl = getLocationType(lht); if (n instanceof NewExp && !((NewExp)n).hasLocal()) { if (!rhtl.isSubtypeOfFarAdapted(lhtl)) { errors.add(new TypeError(n,ErrorMessage.LOCATION_TYPE_CANNOT_ASSIGN,rhtl.toString(),lhtl.toString())); } } else { LocationType adaptedRht = rhtl; if (adaptTo != null) { adaptedRht = rhtl.adaptTo(getLocationType(adaptTo), dir); } if (!adaptedRht.isSubtypeOf(lhtl)) { errors.add(new TypeError(n,ErrorMessage.LOCATION_TYPE_CANNOT_ASSIGN,adaptedRht.toString(),lhtl.toString())); } } } @Override public void annotateType(Type t, ASTNode<?> origNode, ASTNode<?> typeNode) { if (origNode instanceof AsyncCall) { AsyncCall ac = (AsyncCall) origNode; adaptTo(t,AdaptDirection.FROM,ac.getCallee().getType()); } else if (origNode instanceof ThisExp) { setLocationType(t,LocationType.NEAR); } else if (origNode instanceof NewExp) { NewExp newExp = (NewExp)origNode; LocationType type = LocationType.FAR; if (newExp.hasLocal()) { type = LocationType.NEAR; } setLocationType(t,type); } else if (origNode instanceof NullExp) { setLocationType(t, LocationType.BOTTOM); } else if (t.isReferenceType()) { setAnnotatedType(t, origNode); } } private void setAnnotatedType(Type t, ASTNode<?> origNode) { try { LocationType lt = getLocationTypeFromAnnotations(t, origNode); if (lt == null) lt = defaultType; setLocationType(t, lt); } catch (LocationTypeCheckerException e) { errors.add(e.getTypeError()); } } public static LocationType getLocationTypeFromAnnotations(Type t) { return getLocationTypeFromAnnotations(t, null); } public static LocationType getLocationTypeFromAnnotations(Type t, ASTNode<?> originatingNode) { LocationType res = null; for (TypeAnnotation an : t.getTypeAnnotations()) { if (an.getType().getQualifiedName().equals("ABS.StdLib.LocationType")) { DataConstructorExp de = (DataConstructorExp) an.getValue(); String name = de.getDecl().getName(); if (res != null) { throw new LocationTypeCheckerException(new TypeError(an.getValue(),ErrorMessage.LOCATION_TYPE_MULTIPLE, new String[0])); } else { res = LocationType.createFromName(name); } } } /* if (originatingNode != null && originatingNode instanceof ConstructorArg) { if (res == null || !res.isSomewhere()) { throw new LocationTypeCheckerException(new TypeError(originatingNode,ErrorMessage.LOCATION_TYPE_DATACONSTR_MUST_BE_SOMEWHERE, new String[0])); } }*/ return res; } @Override public void checkMethodCall(Call call) { LocationType lt = getLocationType(call.getCallee().getType()); if (lt.isBottom()) { errors.add(new TypeError(call,ErrorMessage.LOCATION_TYPE_CALL_ON_BOTTOM,new String[0])); } else if (call instanceof SyncCall) { if (!lt.isNear()) { errors.add(new TypeError(call,ErrorMessage.LOCATION_TYPE_SYNC_CALL_ON_NON_NEAR,new String[0])); } } } public LocationType getLocationType(Type type) { if (ltie != null) { Map<LocationTypeVariable, LocationType> locationTypeInferenceResult = ltie.getResults(); if (locationTypeInferenceResult != null) { LocationTypeVariable lv = LocationTypeInferrerExtension.getLV(type); if (lv != null) { return defaultIfNull(locationTypeInferenceResult.get(lv)); } } } return defaultIfNull((LocationType) type.getMetaData(LocationType.LOCATION_KEY)); } private LocationType defaultIfNull(LocationType l) { if (l == null) return defaultType; else return l; } public void setLocationType(Type type, LocationType lt) { type.addMetaData(LocationType.LOCATION_KEY, lt); } public void adaptTo(Type type, AdaptDirection dir, Type to) { setLocationType(type,getLocationType(type).adaptTo(getLocationType(to), dir)); } }