feasibleAlternatives returns feasible alternatives for a subgoal p(e1...eN). We consider a relation type expression (from decl), the given list of arguments, the type assignments to variable symbols, and a type context that collects type variables with associated type constrains. Returns list of alt
( pred ast.PredicateSym, relTypeExpr ast.BaseTerm, args []ast.BaseTerm, varRanges map[ast.Variable]ast.BaseTerm, typeCtx map[ast.Variable]ast.BaseTerm)
| 1105 | // that collects type variables with associated type constrains. |
| 1106 | // Returns list of alternatives and list of type contexts with new type constraints. |
| 1107 | func (bc *BoundsAnalyzer) feasibleAlternatives( |
| 1108 | pred ast.PredicateSym, relTypeExpr ast.BaseTerm, args []ast.BaseTerm, |
| 1109 | varRanges map[ast.Variable]ast.BaseTerm, |
| 1110 | typeCtx map[ast.Variable]ast.BaseTerm) ([]ast.BaseTerm, []map[ast.Variable]ast.BaseTerm, error) { |
| 1111 | if pred.Symbol == symbols.ListMember.Symbol { |
| 1112 | tpe := boundOfArg(args[1], varRanges, bc.nameTrie) |
| 1113 | if tpe == ast.AnyBound { |
| 1114 | return []ast.BaseTerm{symbols.NewRelType(ast.AnyBound, symbols.NewListType(ast.AnyBound))}, nil, nil |
| 1115 | } |
| 1116 | if symbols.IsListTypeExpression(tpe) { |
| 1117 | elemTpe, err := symbols.ListTypeArg(tpe) |
| 1118 | if err != nil { |
| 1119 | return nil, nil, err |
| 1120 | } |
| 1121 | var bound ast.BaseTerm |
| 1122 | if v, ok := args[0].(ast.Variable); ok { |
| 1123 | if _, ok := varRanges[v]; ok { |
| 1124 | bound = varRanges[v] |
| 1125 | } else { |
| 1126 | bound = elemTpe // a new variable binding |
| 1127 | } |
| 1128 | } else { |
| 1129 | bound = boundOfArg(args[0], varRanges, bc.nameTrie) |
| 1130 | } |
| 1131 | // TODO: typing context must give lower bounds as well. |
| 1132 | meet := symbols.LowerBound(typeCtx, []ast.BaseTerm{bound, elemTpe}) |
| 1133 | if !meet.Equals(symbols.EmptyType) { |
| 1134 | return []ast.BaseTerm{symbols.NewRelType(meet, tpe)}, []map[ast.Variable]ast.BaseTerm{typeCtx}, nil |
| 1135 | } |
| 1136 | return nil, nil, fmt.Errorf("pred %v on args %v cannot succeed var ranges %v", pred, args, varRanges) |
| 1137 | } |
| 1138 | } |
| 1139 | if pred.Symbol == symbols.MatchPrefix.Symbol { |
| 1140 | tpe := boundOfArg(args[0], varRanges, bc.nameTrie) |
| 1141 | prefix := args[1] |
| 1142 | meet := symbols.LowerBound(nil /*TODO*/, []ast.BaseTerm{tpe, prefix}) |
| 1143 | if !meet.Equals(symbols.EmptyType) { |
| 1144 | return []ast.BaseTerm{symbols.NewRelType(meet, ast.NameBound)}, []map[ast.Variable]ast.BaseTerm{typeCtx}, nil |
| 1145 | } |
| 1146 | return nil, nil, fmt.Errorf("pred %v cannot succeed: type %v is incompatible with %v", pred, tpe, prefix) |
| 1147 | } |
| 1148 | |
| 1149 | if pred.Symbol == symbols.MatchEntry.Symbol { |
| 1150 | tpe := boundOfArg(args[0], varRanges, bc.nameTrie) |
| 1151 | if symbols.IsMapTypeExpression(tpe) { |
| 1152 | keyType, valTpe, err := symbols.MapTypeArgs(tpe) |
| 1153 | if err != nil { |
| 1154 | return nil, nil, err |
| 1155 | } |
| 1156 | var bound ast.BaseTerm |
| 1157 | if v, ok := args[1].(ast.Variable); ok { |
| 1158 | if _, ok := varRanges[v]; ok { |
| 1159 | bound = varRanges[v] |
| 1160 | } else { |
| 1161 | bound = tpe // a new variable binding |
| 1162 | } |
| 1163 | } else { |
| 1164 | bound = boundOfArg(args[1], varRanges, bc.nameTrie) |
no test coverage detected