     # log fixedVars, (printType constraint), (findUnconstrained constraint)
     isSubset fixedVars, (findUnconstrained constraint)
   [deferred, retained] = partition isFixed, impliedConstraints
-  # TODO: handle ambiguity when reducedConstraints include variables not in
-  # fixedVars or quantifiedVars
-  success: [deferred, retained]
+  quantifiedVars = findFree finalType = substitute ctx.substitution, type
+  isAmbiguous = (constraint) ->
+    not isSubset quantifiedVars, (findUnconstrained constraint)
+  [ambiguous, retained] = partition isAmbiguous, retained
+  if _notEmpty ambiguous
+    {error:
+      substitutionFail
+        message: "Constraint #{printType ambiguous[0]} is ambiguous for inferred type #{printType finalType}"
+        conflicts: [type.origin, ambiguous[0].origin]}
+  else
+    success: [deferred, retained]
 
 reduceConstraints = (ctx, constraints) ->
   normalized = normalizeConstraints ctx, constraints

  findFreeInList map subbed, setToArray varNames

# Returns deferred and retained constraints
deferConstraints = (ctx, constraints) ->
  reducedConstraints = reduceConstraints ctx, constraints
  if not reducedConstraints.success
    return reducedConstraints

    currentType = substitute ctx.substitution, type
    # log "assign type", name, (printType (addConstraints currentType, retainedConstraints)), (printType quantifyUnbound ctx, (addConstraints currentType, retainedConstraints))
    if includesJsType currentType.type
      ctx.extendSubstitution substitutionFail "#{name}'s inferred type #{plainPrettyPrint currentType} includes Js"
    else
      ctx.assignType name,
        if polymorphic
