/// <summary> /// If arg : argType must be a subtype of acceptingType, then returns /// a possibly coerced term satisfying the property. The type of the /// coerced term is also returned. /// /// Returns null and generates errors of if the term cannot be /// coerced. /// /// If computeType is false, then the type of the coerced /// term is not returned. /// </summary> private Tuple <Term, Term> Coerce(AppFreeCanUnn acceptingType, Term arg, Term argType, int argIndex, Node appNode, string appFun, List <Flag> flags) { bool wasAdded; Set <Namespace> spaces; Namespace maxPrefix = null; LiftedBool isCoercable = LiftedBool.True; Set <UserSymbol> dataSorts = null; Term resultType = null; UserSymbol us; UserSortSymb uss; //// Step 1. Check that all constants are accepted, and all data sorts //// can potentially be coerced. //// After this loop, resultType contains all constants. argType.Visit( x => x.Symbol == theUnnSymbol ? x.Args : null, t => { if (t.Symbol == theUnnSymbol) { return; } else if (t.Symbol.Kind == SymbolKind.UserSortSymb || t.Symbol.IsDataConstructor || t.Symbol.IsDerivedConstant || (t.Symbol.Kind == SymbolKind.UserCnstSymb && ((UserCnstSymb)t.Symbol).IsTypeConstant)) { if (t.Symbol.Kind == SymbolKind.UserSortSymb) { uss = (UserSortSymb)t.Symbol; us = uss.DataSymbol; } else if (t.Symbol.IsDataConstructor) { us = (UserSymbol)t.Symbol; uss = us.Kind == SymbolKind.ConSymb ? ((ConSymb)us).SortSymbol : ((MapSymb)us).SortSymbol; } else { uss = null; us = (UserSymbol)t.Symbol; } if (maxPrefix == null) { maxPrefix = us.Namespace; } else { us.Namespace.TryGetPrefix(maxPrefix, out maxPrefix); } if (dataSorts == null) { dataSorts = new Set <UserSymbol>(Symbol.Compare); } dataSorts.Add(us); if (!acceptingType.Contains(uss == null ? (Symbol)us : uss)) { if (!acceptingType.TryGetRenamings(us.Name, out spaces)) { var flag = new Flag( SeverityKind.Error, appNode, Constants.UnsafeArgType.ToString( argIndex + 1, appFun, t.Symbol.PrintableName), Constants.UnsafeArgType.Code); flags.Add(flag); isCoercable = LiftedBool.False; } else if (isCoercable == LiftedBool.True) { isCoercable = LiftedBool.Unknown; } } } else if (!acceptingType.AcceptsConstants(t)) { var flag = new Flag( SeverityKind.Error, appNode, Constants.UnsafeArgType.ToString( argIndex + 1, appFun, t.Symbol != theRngSymbol ? t.Symbol.PrintableName : (t.Args[0].Symbol.PrintableName + ".." + t.Args[1].Symbol.PrintableName)), Constants.UnsafeArgType.Code); flags.Add(flag); isCoercable = LiftedBool.False; } else { resultType = resultType == null ? t : Index.MkApply(theUnnSymbol, new Term[] { t, resultType }, out wasAdded); } }); if (isCoercable == false) { return(null); } else if (isCoercable == true) { return(new Tuple <Term, Term>(arg, argType)); } //// Step 2. Check that there is a unique coercion from the user sorts. Contract.Assert(dataSorts != null && maxPrefix != null); Set <Namespace> rnmgs = null, cndts; Namespace prefix; string[] suffix; foreach (var s in dataSorts) { suffix = s.Namespace.Split(maxPrefix); Contract.Assert(suffix != null); acceptingType.TryGetRenamings(s.Name, out spaces); cndts = new Set <Namespace>(Namespace.Compare); foreach (var ns in spaces) { if (ns.Split(suffix, out prefix)) { cndts.Add(prefix); } } if (rnmgs == null) { rnmgs = cndts; } else { rnmgs.IntersectWith(cndts); } if (rnmgs.Count == 0) { var flag = new Flag( SeverityKind.Error, appNode, Constants.UncoercibleArgType.ToString( argIndex + 1, appFun, s.PrintableName), Constants.UncoercibleArgType.Code); flags.Add(flag); return(null); } } if (rnmgs.Count != 1) { foreach (var ns in rnmgs) { var flag = new Flag( SeverityKind.Error, appNode, Constants.AmbiguousCoercibleArg.ToString( argIndex + 1, appFun, maxPrefix.FullName, ns.FullName), Constants.AmbiguousCoercibleArg.Code); flags.Add(flag); } return(null); } var from = maxPrefix; var to = rnmgs.GetSomeElement(); Symbol coerced; foreach (var ds in dataSorts) { if (ds.Kind == SymbolKind.UserCnstSymb) { if (!Index.SymbolTable.IsCoercible(ds, from, to, out coerced)) { coerced = null; } } else { uss = ds.Kind == SymbolKind.ConSymb ? ((ConSymb)ds).SortSymbol : ((MapSymb)ds).SortSymbol; if (!Index.SymbolTable.IsCoercible(uss, from, to, out coerced)) { coerced = null; } } if (coerced == null) { var flag = new Flag( SeverityKind.Error, appNode, Constants.UncoercibleArgType.ToString( argIndex + 1, appFun, ds.PrintableName), Constants.UncoercibleArgType.Code); flags.Add(flag); return(null); } else { resultType = resultType == null ? Index.MkApply(coerced, TermIndex.EmptyArgs, out wasAdded) : Index.MkApply( theUnnSymbol, new Term[] { Index.MkApply(coerced, TermIndex.EmptyArgs, out wasAdded), resultType }, out wasAdded); } } typeEnvironment.AddCoercion(appNode, argIndex, from.FullName, to.FullName); var coercedArg = Index.MkApply( Index.SymbolTable.GetOpSymbol(ReservedOpKind.Relabel), new Term[] { Index.MkCnst(from.FullName, out wasAdded), Index.MkCnst(to.FullName, out wasAdded), arg }, out wasAdded); return(new Tuple <Term, Term>(coercedArg, resultType)); }